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

Есть ли среди вариантов ниже верный способ борьбы с ложными пробуждениями при использовании условных переменных?

1) поставить wait(unique_lock_ul) в бесконечность while цикл, используя логическое значение

unique_lock<mutex> ul(m);
while(!full)
cv.wait(ul);

2) То же самое, если

unique_lock<mutex> ul(m);
if(!full)
cv.wait(ul);

3) Поместите условие внутри wait()Например, используя лямбда-функции

unique_lock<mutex> ul(m);
cv.wait(ul, [&](){return !full;});

Если ничего из этого не правильно, как легко справиться с ложными пробуждениями?

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

2

Решение

Короткий ответ: ваш код может быть правильным или неправильным; вы не показали, как именно full манипулируется.

Отдельные биты кода C ++ никогда не являются поточно-ориентированными. Поток безопасности является реляционный свойство кода; два бита кода могут быть потокобезопасными по отношению друг к другу, если они никогда не могут вызвать состояние гонки.

Но один бит кода никогда не является поточно-ориентированным; сказать что-то потокобезопасно — это все равно, что сказать что-то «такой же высоты»


Шаблон переменной условия «monkey see monkey do» таков:

template<class T>
class cv_bundle {
std::mutex m;
T payload;
std::condition_variable cv;
public:
explicit cv_bundle( T in ):payload(std::move(in)) {}

template<class Test, class Extract>
auto wait( Test&& test, Extract&& extract ) {
std::unique_lock<std::mutex> l(m);
cv.wait( l, [&]{ return test(payload); } );
return extract(payload);
}
template<class Setter>
void load( Setter&& setter, bool only_one = true ) {
bool is_set = false;
{
std::unique_lock<std::mutex> l(m);
is_set = setter( payload );
}
if (!is_set) return; // nothing to notify
if (only_one)
cv.notify_one();
else
cv.notify_all();
}
};

test занимает T& payload и возвращает true, если есть что потреблять (т. е. пробуждение не поддельное).

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

setter модифицирует T& payload таким образом, что test вернусь true, Если это так, он возвращает true, Если он решит не делать, он вернется false,

Все 3 вызывались в мьютексе, блокирующем доступ к T payload,

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

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

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

По сути, я избегаю оставлять этот стиль использования условных переменных в стиле «культ груза», если только у меня нет веских причин. И затем я вынужден прочитать модель памяти и многопоточности C ++, которая не делает мой день, и это означает, что мой код, скорее всего, не будет правильным.

Обратите внимание, что если какой-либо из лямбд перешел в иди и перезвонить в cv_bundle код, который я показал, больше не действителен.

2

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

Либо 1, либо 3 способ хороши для борьбы с ложными пробуждениями (при условии, что full модификация защищена тем же мьютексом) за исключением неверного условия предиката, оно должно быть:

unique_lock<mutex> ul(m);
cv.wait(ul, [&](){return full;});

сделать этот код равным варианту 1.

Вариант 2 не подходит, хотя при ложном пробуждении условие ожидания не будет перепроверено, в отличие от 2 других случаев.

2

По вопросам рекламы [email protected]