Условные переменные и контейнер без блокировки

Условные переменные используют мьютекс, а функция .wait () разблокирует
мьютекс, чтобы другой поток мог получить доступ к общим данным. Когда состояние
переменная уведомляется, она пытается снова заблокировать мьютекс, чтобы использовать общий
данные.

Этот шаблон используется в следующем примере concurrent_queue из Энтони Уильямс:

template<typename Data>
class concurrent_queue
{
private:
boost::condition_variable the_condition_variable;
public:
void wait_for_data()
{
boost::mutex::scoped_lock lock(the_mutex);
while(the_queue.empty())
{
the_condition_variable.wait(lock);
}
}
void push(Data const& data)
{
boost::mutex::scoped_lock lock(the_mutex);
bool const was_empty=the_queue.empty();
the_queue.push(data);
if(was_empty)
{
the_condition_variable.notify_one();
}
}
};

Поскольку код использует std :: queue, ясно, что мьютекс должен быть
заблокирован при доступе к очереди.
Но скажем, вместо std :: queue один Microsofts
Параллелизм :: concurrent_queue
из ппл. Функции-члены как пустой,
push и try_pop являются потокобезопасными. Мне все еще нужно заблокировать мьютекс в
в этом случае или можно использовать условную переменную без
создание любых возможных условий гонки.

Мой код (кажется, работает, но что это значит в многопоточности?) Выглядит следующим образом. У меня есть один производитель, который помещает элементы в Microsoft concurrent_queue и один фоновый поток, который ждет новых элементов в этой очереди.

Потребительский / фоновый поток:

while(runFlag) //atomic
{
while(the_queue.empty() && runFlag) //wait only when thread should still run
{
boost::mutex mtx; //local mutex thats locked afterwards. awkward.
boost::mutex::scoped_lock lock(mtx);
condition.wait(lock);
}

Data d;
while(!the_queue.empty() && the_queue.try_pop(d))
{
//process data
}
}

Производитель / основная тема:

const bool was_empty = the_queue.empty();
Data d;
the_queue.push(d);
if(was_empty) cond_var.notify_one();

Процедура выключения:

bool expected_run_state = true;
if(runLoop.compare_exchange_strong(expected_run_state, false))
{
//atomically set our loop flag to false and
//notify all clients of the queue to wake up and exit
cond_var.notify_all();
}

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

if(the_queue.empty()) Sleep(short_amount_of_time);

Существуют ли какие-либо другие, возможно, ОС (в моем случае: Windows) специальные инструменты, которые переводят фоновый поток в спящий режим до тех пор, пока не будет выполнено какое-либо условие без регулярного пробуждения и проверки состояния?

3

Решение

Например, код неверен в разных сценариях. Если очередь имеет один элемент, когда const bool was_empty = the_queue.empty(); оценивается, но поток потребляет элемент, а другой поток пытается потреблять и ожидает выполнения условия, писатель не будет уведомлять этот поток после вставки элемента в очередь.

Ключевой вопрос заключается в том, что тот факт, что все операции в интерфейсе являются потокобезопасными, не обязательно означает, что использование вами интерфейса безопасно. Если вы зависите от нескольких операций, выполняемых атомарно, вам необходимо предоставить механизмы синхронизации извне.

1

Другие решения

Существуют ли другие, возможно, ОС (в моем случае: Windows) специальные инструменты,
которые заставляют фоновый поток спать до тех пор, пока не будет выполнено некоторое условие
без регулярного пробуждения и проверки состояния?

Это именно то, что События для

Но если вы ориентируетесь только на платформу Windows (Vista +), вы должны проверить
Тонкие замки для чтения / записи (SRW)

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector