boost::condition_variable
От: enji  
Дата: 11.04.11 08:47
Оценка: 4 (1)
Здравствуйте

Читаю доку boost::thread и не пойму, почему condition_variable сделан именно так.

Хочется чего-то вроде обычного event, с примерно таким использованием:

event evl;

void thread1()
{
  // готовим какие-то данные
  ev1.raise();
}

void thread2()
{
  ev1.wait();
  // данные готовы
}


Однако с использованием condition_variable это превращается в:
bool ev1_var;
condition_variable ev1_cond;
mutex ev1_mut;

void thread1()
{
  // готовим какие-то данные
  ev1_var = true;
  ev1_cond.notify_one();
}

void thread2()
{
    unique_lock<mutex> lock(ev1_mut);
    while(!ev1_var)    
        ev1_cond.wait(lock);        
    // данные готовы

}


Как-то очень многословно получается... Зачем вообще такая "сложная" схема применения нужна? Или я чего-то не понимаю — наставьте на путь истинный

Спасибо!
Re: boost::condition_variable
От: placement_new  
Дата: 11.04.11 09:18
Оценка:
Здравствуйте, enji, Вы писали:

E>Здравствуйте


E>Читаю доку boost::thread и не пойму, почему condition_variable сделан именно так.


E>Хочется чего-то вроде обычного event, с примерно таким использованием:


E>
E>event evl;

E>void thread1()
E>{
E>  // готовим какие-то данные
E>  ev1.raise();
E>}

E>void thread2()
E>{
E>  ev1.wait();
E>  // данные готовы
E>}

E>


E>Однако с использованием condition_variable это превращается в:

E>
E>bool ev1_var;
E>condition_variable ev1_cond;
E>mutex ev1_mut;

E>void thread1()
E>{
E>  // готовим какие-то данные
E>  ev1_var = true;
E>  ev1_cond.notify_one();
E>}

E>void thread2()
E>{
E>    unique_lock<mutex> lock(ev1_mut);
E>    while(!ev1_var)    
E>        ev1_cond.wait(lock);        
E>    // данные готовы

E>}
E>


E>Как-то очень многословно получается... Зачем вообще такая "сложная" схема применения нужна? Или я чего-то не понимаю — наставьте на путь истинный


E>Спасибо!


Можешь сделать обертку Event надо condition variable.
Condition variable гибче.
Re: boost::condition_variable
От: kvser  
Дата: 11.04.11 09:19
Оценка: -1
Здравствуйте, enji, Вы писали:

E>
E>event evl;

E>void thread1()
E>{
E>  // готовим какие-то данные <-- здесь
E>  ev1.raise();
E>}

E>void thread2()
E>{
E>  ev1.wait();
E>  // данные готовы <--- и здесь может быть одновременный доступ к одному и отму же ресурсу (данным)
E>}

E>


Например, когда 2 поток данные еще не успел обработать, а первый начал уже готовить новые

E>Однако с использованием condition_variable это превращается в:

E>
E>bool ev1_var;
E>condition_variable ev1_cond;
E>mutex ev1_mut;

E>void thread1()
E>{
lock<mutex> lock(ev1_mut);
E>  // готовим какие-то данные <-- мьютекс залочен
E>  ev1_var = true;
E>  ev1_cond.notify_one();
E>}

E>void thread2()
E>{
E>    unique_lock<mutex> lock(ev1_mut);
E>    while(!ev1_var)    
E>        ev1_cond.wait(lock);        
E>    // данные готовы <-- мьютекс залочен

E>}
E>
Re: boost::condition_variable
От: uzhas Ниоткуда  
Дата: 11.04.11 12:52
Оценка:
Здравствуйте, enji, Вы писали:

E>Хочется чего-то вроде обычного event

в гугле нашлось: http://www.rsdn.ru/forum/cpp/636650.all.aspx
Автор: maq
Дата: 12.05.04
Re[2]: boost::condition_variable
От: kvser  
Дата: 11.04.11 13:23
Оценка:
Здравствуйте, uzhas, Вы писали:

как-нибудь уж прокомментируйте
Re[2]: boost::condition_variable
От: placement_new  
Дата: 11.04.11 14:07
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, enji, Вы писали:


E>>Хочется чего-то вроде обычного event

U>в гугле нашлось: http://www.rsdn.ru/forum/cpp/636650.all.aspx
Автор: maq
Дата: 12.05.04


Пост то от 2004 года. С тех библиотека переписана была.
Re: boost::condition_variable
От: uzhas Ниоткуда  
Дата: 11.04.11 14:16
Оценка:
Здравствуйте, enji, Вы писали:

E>Хочется чего-то вроде обычного event, с примерно таким использованием:


лучшие собаководы рекомендуют такой подход (метакод):
  Скрытый текст
class Event
{
public:
  Event()
    : IsSet(false)
  {
  }

  void Set()
  {
    Lock lock(Monitor);
    IsSet = true;
    Cond.notify_one();
  }

  void Reset()
  {
    Lock lock(Monitor);
    IsSet = false;
  }

  void Wait()
  {
    Lock lock(Monitor);
    while (!IsSet)
    {
      Cond.wait(lock);
    }

    IsSet = false;
  }

private:
  bool IsSet;
  mutex Monitor;
  condition_variable Cond;
};

мопед не мой, я его только опубликовал
Re[3]: boost::condition_variable
От: uzhas Ниоткуда  
Дата: 11.04.11 14:20
Оценка:
Здравствуйте, placement_new, Вы писали:
_>Пост то от 2004 года. С тех библиотека переписана была.
что поменялось касательно вопроса TC ?
Re[3]: boost::condition_variable
От: kvser  
Дата: 11.04.11 14:37
Оценка: +1
K>Здравствуйте, uzhas, Вы писали:

Да, действительно, я этот пример
E>event evl;

E>void thread1()

E>{
E> // готовим какие-то данные
E> ev1.raise();
E>}

E>void thread2()

E>{
E> ev1.wait();
E> // данные готовы
E>
}
переварил как следующий (обычная ситуация)
E>void thread1()
E>{
while(что-то там)// данные готовы
{
E> // готовим какие-то данные
E> ev1.raise();
}
E>}

E>void thread2()

E>{
while(что-то там)
{
E> ev1.wait();
E> // данные готовы
}
E>}

потому и комментарий такой написал
Re[4]: boost::condition_variable
От: kvser  
Дата: 11.04.11 15:27
Оценка:
И, кстати, для случая когда в потоках выполняется цикл, в пример с condition_variable надо добавить всего одну строку, как я показал здесь
Автор: kvser
Дата: 11.04.11
.
А как будет выглядеть пример с использованием event? Потребуется второй объект event?

З.Ы. И в обоих таких случаях получается отсутствие распараллеливания. Каждый поток сначала ждет другой, чтобы выполнить свою работу. Очередь сразу напрашивается.
Re[2]: boost::condition_variable
От: uzhas Ниоткуда  
Дата: 11.04.11 15:34
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, enji, Вы писали:


E>>Хочется чего-то вроде обычного event, с примерно таким использованием:


U>лучшие собаководы рекомендуют такой подход (метакод):


у этого подхода есть нюанс : кол-во Set не гарантирует столько же отпусканий ждущих потоков
то есть если у вас есть 2 ждущих потока, и вы делаете из третьего два раза Set, то не гарантировано, что оба ждущих потока пройдут
как я понимаю, аналогичное поведение у виндового Event-а
Re[3]: boost::condition_variable
От: kvser  
Дата: 11.04.11 15:57
Оценка:
Здравствуйте, uzhas, Вы писали:

U>то есть если у вас есть 2 ждущих потока, и вы делаете из третьего два раза Set, то не гарантировано, что оба ждущих потока пройдут


это в том случае, если в третьем потоке вызвался второй Set до того как один из ждущих успел проснуться? Эта ситауция эквивалента такому вызову:
    {
      Lock lock(Monitor);
      IsSet = true;
      Cond.notify_one();
....
      IsSet = true;
      Cond.notify_one();
    }


Это возможно, если количество вызовов notify_one() не гарантирует такое же количество просыпаний
Re[4]: boost::condition_variable
От: uzhas Ниоткуда  
Дата: 11.04.11 18:06
Оценка:
Здравствуйте, kvser, Вы писали:

K>Это возможно, если количество вызовов notify_one() не гарантирует такое же количество просыпаний

да, я ошибся
нюанс не относится к Event-у
Re[5]: boost::condition_variable
От: kvser  
Дата: 11.04.11 19:59
Оценка:
Здравствуйте, uzhas, Вы писали:
K>>Это возможно, если количество вызовов notify_one() не гарантирует такое же количество просыпаний
U>да, я ошибся
не ошибся

потоки проснуться, один из них захватит мьютекс(другой будет заблокирован в ожидании мьютекса), переменной IsSet присвоит false и освободит мьютекс. Далее другой захватит мьютекс, проверит условие !IsSet, которое окажется верным, и опять уйдет в ожидание в wait()
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.