ПроблемаФункция, которая может побочно проснуться не перенесенный в цикл, происходит, когда следующие функции ожидания при условии вызваны снаружи цикла:
Функции ожидания при условии приостанавливают выполнение вызывающего потока, когда заданное условие соблюдают. Поток просыпается и возобновляется, если другой поток уведомляет его с 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, который уведомляет все потоки. Это уведомление заставляет поток просыпаться, даже если условие паузы все еще верно.
Коррекция — переносит 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 в цикле неявноstd::condition_variable::wait функция имеет перегрузку, которая принимает функцию lambda как второй аргумент. Предикат функции Lambda указывает, когда безопасно прекратить ожидать и возобновлять выполнение кода. Эта перегрузка std::condition_variable::wait функция ведет себя, как будто она неявно перенесена в цикл. В этом коде, functionstd::condition_variable::wait вызывается при помощи функции Lambda. Здесь, нежелательное пробуждение потока предотвращено, потому что поток просыпается, когда предикат функции Lambda верен.
#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); });
}