ПроблемаФункция, которая может ложно проснуться, не обернутая в цикл, возникает, когда следующие функции ожидания условия вызываются из-за пределов цикла:
Функции ожидания зависят от выполнения вызывающего потока при выполнении заданного условия. Поток просыпается и возобновляется, когда другой поток уведомляет его с cnd_broadcast()
или эквивалентную функцию. Уведомление о пробуждении может быть ложным или вредоносным.
РискЕсли поток получает ложное уведомление о пробуждении и условие функции ожидания не проверяется, поток может проснуться преждевременно. Пробуждение может вызвать неожиданный поток управления, неопределенную блокировку других потоков или отказ в обслуживании.
ЗафиксироватьОберните функции ожидания при условии, которые могут ложно проснуться в цикле. Цикл проверяет условие пробуждения после возможного ложного уведомления о пробуждении.
Пример - std::condition_variable::wait
Не обернутый в цикл#include <stdio.h>
#include <stddef.h>
#include <thread>
#include <mutex>
#define THRESHOLD 100
std::mutex myMutex;
std::condition_variable cv;
void func(int input)
{
std::unique_lock<std::mutex> lk(myMutex);
// test condition to pause thread
if (input > THRESHOLD) {
//pause current thread
cv.wait(lk);//Noncompliant
}
}
В этом примере поток использует std::condition_variable::wait
для паузы выполнения при input
больше THRESHOLD
. Приостановленный поток может возобновиться, если другой поток использует std::condition_variable::notify_all
, который уведомляет все потоки. Это уведомление заставляет поток просыпаться, даже если условие паузы все еще соответствует true.
Коррекция - Обернуть std::condition_variable::wait
в while
Цикл явноОдной из возможных коррекций является перенос вызова в std::condition_variable::wait
в while
цикл. Цикл проверяет условие паузы после получения потоком возможного ложного уведомления о пробуждении.
#include <stdio.h>
#include <stddef.h>
#include <thread>
#include <mutex>
#define THRESHOLD 100
std::mutex myMutex;
std::condition_variable cv;
void func(int input)
{
std::unique_lock<std::mutex> lk(myMutex);
// test condition to pause thread
while (input > THRESHOLD) {
//pause current thread
cv.wait(lk);
}
}
Коррекция - Обернуть std::condition_variable::wait
в цикле неявноThe std::condition_variable::wait
функция имеет перегрузку, которая принимает лямбда-функцию как второй аргумент. Предикат функции Lambda указывает, когда безопасно остановить ожидание и продолжить выполнение кода. Эта перегрузка std::condition_variable::wait
функция ведет себя так, как если бы она была неявно завёрнута в цикл. В этом коде функция std::condition_variable::wait
вызывается с помощью функции Lambda. Здесь нежелательное пробуждение потока предотвращается, потому что поток просыпается, когда предикат функции Lambda равен true.
#include <stdio.h>
#include <stdio.h>
#include <stddef.h>
#include <thread>
#include <mutex>
#define THRESHOLD 100
std::mutex myMutex;
std::condition_variable cv;
void func(int input)
{
std::unique_lock<std::mutex> lk(myMutex);
cv.wait(lk,[&input]{ return !(input>THRESHOLD); });
}