exponenta event banner

Function that can spuriously wake up not wrapped in loop

Цикл проверяет условие пробуждения после возможного ложного пробуждения

Описание

Этот дефект возникает, когда следующие функции ожидания вызываются из-за цикла:

  • Функции C:

    • cnd_wait()

    • cnd_timedwait()

  • Функции POSIX:

    • pthread_cond_wait()

    • pthread_cond_timedwait()

  • C++ std::condition_variable и std::condition_variable_any функции члена класса:

    • wait()

    • wait_until()

    • wait_for()

Функции ожидания зависят от выполнения вызывающего потока при выполнении заданного условия. Поток просыпается и возобновляется, когда другой поток уведомляет его с cnd_broadcast() или эквивалентную функцию. Уведомление о пробуждении может быть ложным или вредоносным.

Риск

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

Зафиксировать

Оберните функции ожидания при условии, которые могут ложно проснуться в цикле. Цикл проверяет условие пробуждения после возможного ложного уведомления о пробуждении.

Примеры

расширить все

#include <stdio.h>
#include <stddef.h>
#include <threads.h>

#define THRESHOLD 100

static mtx_t lock;
static cnd_t cond;

void func(int input)
{
    if (thrd_success != mtx_lock(&lock)) {
        /* Handle error */
    }
    /* test condition to pause thread */
    if (input > THRESHOLD) {
        if (thrd_success != cnd_wait(&cond, &lock)) {
            /* Handle error */
        }
    }
    /* Proceed if condition to pause does not hold */


    if (thrd_success != mtx_unlock(&lock)) {
        /* Handle error */
    }
}

В этом примере поток использует cnd_wait() для паузы выполнения при input больше THRESHOLD. Приостановленный поток может возобновиться, если другой поток использует cnd_broadcast(), который уведомляет все потоки. Это уведомление заставляет поток просыпаться, даже если условие паузы все еще соответствует true.

Коррекция - Обернуть cnd_wait() в while Цикл

Одной из возможных коррекций является обертывание cnd_wait() в while цикл. Цикл проверяет условие паузы после получения потоком возможного ложного уведомления о пробуждении.

#include <stdio.h>
#include <stddef.h>
#include <threads.h>

#define THRESHOLD 100

static mtx_t lock;
static cnd_t cond;

void func(int input)
{
    if (thrd_success != mtx_lock(&lock)) {
        /* Handle error */
    }
    /* test condition to pause thread */
    while (input > THRESHOLD) {
        if (thrd_success != cnd_wait(&cond, &lock)) {
            /* Handle error */
        }
    }
    /* Proceed if condition to pause does not hold */


    if (thrd_success != mtx_unlock(&lock)) {
        /* Handle error */
    }
}
 

Информация о результатах

Группа: Параллелизм
Язык: C | C++
По умолчанию: Off
Синтаксис командной строки : SPURIOUS_WAKEUP_NOT_WRAPPED_IN_LOOP
Влияние: Низкое
Введенный в R2018b