2010-03-19 2 views
15

Я пытаюсь узнать переменные состояния. Я хотел бы знать, каковы обычные ситуации, когда используются переменные условия.Каковы общие применения переменных состояния в C++?

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

Каковы другие проектные ситуации, в которых вам нужна переменная условия для использования?

Я бы предпочел примеры, основанные на опыте, например, в реальных реальных приложениях.

+1

Должно ли это быть wiki сообщества? – jasonline

+0

Поскольку вы не ищете конкретного ответа и, скорее всего, более общие «ответы». Но я больше нахожусь на заборе этого, вам, возможно, захочется дождаться ния или yay от других. – GManNickG

+2

+1 Возьмите эти хорошо заработанные очки репутации, пока вы можете это ответить :-) –

ответ

2

Одно использование переменных условий, которые немного сложнее, чем просто очередь сообщений, заключается в «совместном использовании блокировки», где разные потоки ожидают тонко отличающихся условий одного и того же основного характера. Например, у вас есть (очень шонкий, упрощенный) веб-кеш. Каждая запись в кеше имеет три возможных состояния: нет, IN_PROGRESS, COMPLETE.

getURL: 
    lock the cache 
    three cases for the key: 
     not present: 
      add it (IN_PROGRESS) 
      release the lock 
      fetch the URL 
      take the lock 
      update to COMPLETE and store the data 
      broadcast the condition variable 
      goto COMPLETE 
     COMPLETE: 
      release the lock and return the data 
     IN_PROGRESS: 
      while (still IN_PROGRESS): 
       wait on the condition variable 
      goto COMPLETE 

У меня на практике использовал шаблон для реализации варианта функции POSIX pthread_once без какой-либо помощи от планировщика. Причина, по которой я не мог использовать семафор или блокировку за once_control, и просто выполнить инициализацию под замком, заключается в том, что функции не разрешалось сбой, а once_control имел только тривиальную инициализацию. В этом случае pthread_once сам не имеет определенных кодов ошибок, поэтому реализация его, возможно, сбой не оставляет вашего звонящего с любыми хорошими вариантами ...

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

1

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

+0

@ Майкл: Я не очень хорошо знаком с барьерами ... но в вашем примере вы говорите, что использовали барьеры с отдельной переменной условия? Я думал, что вы можете реализовать вышеупомянутую ситуацию, используя только барьеры и не нуждаясь в отдельной переменной условия? – jasonline

+0

@jasonline, поэтому вы можете использовать барьеры, предоставляемые pthreads, но вы также можете реализовать свой собственный барьер, используя мьютекс и переменную условия (так как pthreads, скорее всего, предоставляет свои собственные). Когда вы входите в барьер, вы блокируете мьютекс, увеличиваете счет и сохраняете смысл барьера. Если счетчик достиг максимального значения, вы сбросите счет до нуля, отмените определение барьера, сигнализируйте состояние и выйдите из барьера. В противном случае вы ждете состояния, пока значение барьера не будет противоположно сохраненному. –

+0

А, да. Я понимаю. Благодарю. – jasonline

0

Я использовал его для отправки синхронизированных сообщений, где был добавлен объект синхронизации.
Объект синхронизации состоял из переменной условия с «готовым» булевым.
В функции syncMsg :: send() была функция sync-> wait(), а в функции syncMsg :: handle() была синхронизация -> go().

Должно использоваться разумно из-за возможных взаимоблокировок.

0

Я использую переменные условия вместо подверженных ошибкам объектов событий Win32. С condvars вам не нужно так беспокоиться о ложной сигнализации. Также легче ждать появления нескольких событий.

Кондравы также могут заменить семафоры, поскольку они более универсальны.

0

Я знаю, что это не очень полезно, но я использую переменную условия в любое время, когда я хочу, чтобы поток ожидал чего-то, или только дождался, пока что-то не произойдет.

Очень распространенный шаблон, в котором я использую переменную условия, представляет собой фоновый поток, который каждые несколько минут просыпается, чтобы выполнить некоторую обработку, а затем возвращается к сна. При выключении основного потока, чтобы сигнализировать фоновый поток, чтобы закончить, а затем присоедините его к завершению. Фоновый поток ожидает состояния с тайм-аутом, чтобы выполнить его сон.

Фоновый поток следует этой базовой логики

void threadFunction() { 
    initialisation(); 

    while(! shutdown()) { 
     backgroundTask(); 

     shutdown_condition_wait(timeout_value); 
    } 

    cleanup(); 
} 

Это позволяет фоновую нить выключение быстро и изящно.

Если у меня есть ряд таких потоков, основная функция сигнализирует каждому об отключении, а затем присоединяется к каждому из них после следующего. Это позволяет параллельному отключению каждого компонента нити.

Смежные вопросы