Можно ли использовать одну переменную условия для двунаправленной синхронизации (то есть два разных условия ожидаются в разное время для одной и той же переменной условия)? Я уверен, что не более одного потока будет ожидать переменную условия в любое время. Пример кода ниже иллюстрирует то, о чем я думаю:
#include <condition_variable>
#include <thread>
#include <mutex>
#include <iostream>
std::condition_variable condvar;
std::mutex mutex;
int i;
void even()
{
while (i < 10000) {
std::unique_lock<std::mutex> lock(mutex);
if (i % 2 != 0) {
condvar.notify_one();
condvar.wait(lock, [&](){ return i % 2 == 0; });
}
i++;
std::cout << i << std::endl;
}
condvar.notify_one();
}
void odd()
{
while (i < 10001) {
std::unique_lock<std::mutex> lock(mutex);
if (i % 2 != 1) {
condvar.notify_one();
condvar.wait(lock, [&](){ return i % 2 == 1; });
}
i++;
std::cout << i << std::endl;
}
}
int main()
{
i = 0;
std::thread a(even);
std::thread b(odd);
a.join();
b.join();
}
Да, это совершенно безопасно. Однако я бы не стал привыкать звонить notify_one
когда вы действительно хотите уведомить все потоки ожидают выполнения условия, даже если вы «знаете», что будет ожидать только один поток.
По сути, уведомление о условной переменной действительно только объявляет, что «возможно, произошло искомое условие».
Единственная проблема, с которой можно столкнуться при двунаправленной связи с одной условной переменной, заключается в том, что поток может быть разбужен уведомлением, когда для него нет доступных данных. Правильное использование условных переменных выполняется в цикле while, поэтому в худшем случае поток видит, что данные недоступны, и возвращается в спящий режим. Это абсолютно безопасно, поэтому возможна двусторонняя связь с одной условной переменной.
Это, как говорится, имеет мало преимуществ для ненужного пробуждения потоков, поэтому обычно предпочтительно иметь один мьютекс, защищающий данные (т.е. вы должны удерживать мьютекс для доступа к данным), и две разные переменные условия, указывающие разные условия. Это минимизирует количество раз, когда вы просыпаетесь от потока, чтобы обнаружить, что у него нет данных для работы (это называется «ложным» уведомлением).