POSIX Threads: Условные переменные - какой смысл? - PullRequest
4 голосов
/ 31 августа 2009

Я недавно довольно много работал с pthreads, и есть одна маленькая вещь, которую я до сих пор не совсем понимаю. Я знаю, что условные переменные предназначены для ожидания выполнения конкретного условия (или его «передачи в сигнале»). У меня вопрос, как это вообще отличается от нормальных мьютексов?

Насколько я понимаю, не являются ли условные переменные просто мьютексом с дополнительной логикой, чтобы разблокировать другой мьютекс (и снова его заблокировать), когда условие становится истинным?

Пример Psuedocode:

mutex mymutex;
condvar mycond;
int somevalue = 0;

onethread()
{
    lock(mymutex);

    while(somevalue == 0)
        cond_wait(mycond, mymutex);

    if(somevalue == 0xdeadbeef)
        some_func()

    unlock(mymutex);
}

otherthread()
{
    lock(mymutex);

    somevalue = 0xdeadbeef;

    cond_signal(mycond);

    unlock(mymutex);
}

Таким образом, cond_wait в этом примере разблокирует mymutex, а затем ожидает сигнала mycond.

Если это так, то не являются ли условные переменные просто мьютексами с дополнительной магией? Или у меня неправильное понимание фундаментальных основ мьютексов и условных переменных?

Ответы [ 3 ]

13 голосов
/ 31 августа 2009

Две структуры совершенно разные. Мьютекс предназначен для предоставления сериализованного доступа к какому-либо ресурсу. Условная переменная предназначена для того, чтобы один поток мог уведомить другой поток о том, что произошло какое-то событие.

12 голосов
/ 31 августа 2009

Они не совсем мьютексы с дополнительной магией, хотя в некоторых абстракциях (монитор используется в java и C #) переменная условия и мьютекс объединяются в одну единицу. Цель условных переменных - избежать ожидания ожидания / опроса и намека на время выполнения, какой поток (ы) должен быть запланирован «следующим». Подумайте, как бы вы написали этот пример без условных переменных.

while(1) {
  lock(mymutex)
  if( somevalue != 0)
     break;
  unlock(mymutex);
}

if( somevalue == 0xdeadbeef )
  myfunc();

Вы будете сидеть в узкой петле в этой ветке, сжигая много процессора и создавая много конфликтов на блокировку. Если блокировка / разблокировка мьютекса достаточно дешевая, вы можете оказаться в ситуации, когда другой поток даже не имеет возможности получить блокировку (хотя мьютексы реального мира обычно различают владелец потока и наличие блокировки, а также понятия справедливости так что вряд ли это произойдет в реальности).

Вы можете уменьшить занятость ожидания, вставая в сон,

while(1) {
  lock(mymutex)
  if( somevalue != 0)
     break;
  unlock(mymutex);
  sleep(1); // let some other thread do work
}

но как долго это хорошее время для сна? Вы просто будете угадывать. Время выполнения также не может сказать, почему вы спите или чего вы ждете. Переменная условия позволяет хотя бы в некоторой степени времени выполнения знать, какие потоки заинтересованы в том же событии в настоящее время.

3 голосов
/ 31 августа 2009

Простой ответ: вы можете захотеть разбудить более одного потока из условных переменных, но мьютекс позволяет только одному потоку выполнять защищенный блок.

...