Что такое общее использование условных переменных в C++?

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

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

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

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

15
задан 2 revs 19 March 2010 в 10:28
поделиться

5 ответов

Одно из вариантов использования условных переменных, которое немного сложнее, чем просто очередь сообщений, - это " совместно использовать блокировку ", где разные потоки ждут слегка разных условий одной и той же базовой природы. Например, у вас есть (очень громоздкий, упрощенный) веб-кеш. Каждая запись в кэше имеет три возможных состояния: отсутствует, 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 сам по себе не имеет определенных кодов ошибок, поэтому его реализация для возможного сбоя не оставляет для вызывающего абонента никаких хороших вариантов ...

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

2
ответ дан 1 December 2019 в 05:26
поделиться

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

Следует использовать с осторожностью из-за возможных тупиков.

0
ответ дан 1 December 2019 в 05:26
поделиться

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

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

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

void threadFunction() {
    initialisation();

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

        shutdown_condition_wait(timeout_value);
    }

    cleanup();
}

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

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

0
ответ дан 1 December 2019 в 05:26
поделиться

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

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

0
ответ дан 1 December 2019 в 05:26
поделиться

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

1
ответ дан 1 December 2019 в 05:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: