LINUX.ORG.RU

условные переменные

 ,


0

3

Здраствуйте. Может ли кто подсказать насчёт безопасности использования условных переменных с блокировкой вида fake_lock?

Краткое описание ситуации: есть некоторое условие, которого нужно уметь ждать из другого потока. Это условие задаётся атомарной переменной, поэтому дополнительная блокировка кажется излишней. Изменения, произведённые рабочим потоком(тот, который атомик выставляет в значение, ожидаемое другими потоками) будут видны в остальных после завершения ожидания, поскольку:

30.5 Condition variables
4 The implementation shall behave as if all executions of notify_one, notify_all, and each part of the wait, wait_for, and wait_until executions are executed in a single unspecified total order consistent with the «happens before» order.

Но есть одна проблема:

30.5 Condition variables
3 The execution of wait, wait_for, and wait_until shall be performed in three atomic parts:
1. the release of the mutex and entry into the waiting state;
2. the unblocking of the wait; and
3. the reacquisition of the lock.

- проверка предиката и переход в состояние ожидания выполняются НЕ атомарно.

Это означает возможность потери сигнала пробуждения?

Deleted

Там не сигнал, а «положено и лежит» значение в переменной. При следующей проверке пролоезет, авось.

anonymous ()
Ответ на: комментарий от anonymous

При следующей проверке

Так её не будет - поток спит же

Deleted ()

Где вы condition variable возмете которая без мутекса работает ?

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

They are called with mutex locked by the calling thread or undefined behaviour will result.

А всякие STL и BOOST в конечном итоге мапятся в pthread (под linux)

zaz ★★★★ ()

Потери сигнала не будет только если соблюдать правило о том, что - метод notify обязательно вызывать под той же захваченной блокировкой (согласно задумке изобретателей паттерна condition variable, как в pthreads).

А поскольку между тем как выполняется проверка предиката и переход в состояние ожидания - блокировка захвачена проверяющим потоком - за это время сигнал никто послать не сможет.

GPFault ★★ ()
Ответ на: комментарий от aureliano15

... нужен код ...

Не компилирующийся пример, конечно, но думаю ситуацию прояснит:

struct lock
{
    void lock() {}
    void unlock() {}
};

std::atomic<unsigned char> c = 0;
lock l;
std::condition_variable_any cv;

void control()
{
    //передаём рабочему потоку нечто на исполнение,
    //запускается он в другом месте
    ...
    //здесь надо подождать завершения исполнения задачи и,
    //например, забрать результат
    std::unique_lock<...> lock(l);
    cv.wait(lock, [](){ return c == 5; });
    //что-то делаем с результатами
    ...
}

void worker()
{
    //ждём задачу, как придёт - начинаем исполнение
    ...
    //после исполнения выставляем флаг готовности
    c=5;
    cv.notify_all();
    //goto 1;
}
Глобальные объекты здесь для простоты(вместе с данными конкретной задачи лежат). В чём проблема: вызов notify_all() между первой проверкой предиката и засыпанием в wait(). Теряется ли сигнал пробуждения в этом случае(и один поток навсегда засыпает)?

Deleted ()
Ответ на: комментарий от zaz

Есть std::condition_variable_any<>, которая работает с BasicLockable типом(вместо мьютекса). Можно, конечно, посмотреть как всё сделано в gcc, но это ж конкретная реализация, да ещё и конкретной версии - поэтому стандарт пытаюсь раскурить

Deleted ()
Ответ на: комментарий от GPFault

Я понял вашу мысль, сам также рассуждаю. Но

метод notify обязательно вызывать под той же захваченной блокировкой

В крестах такого требования нет(???)

Deleted ()

проверка предиката и переход в состояние ожидания выполняются НЕ атомарно.

А как оно будет атомарно, если там произвольный код?

Это означает возможность потери сигнала пробуждения?

Судя по всему, да, но это не должно быть проблемой в общем случае, потому что должен быть мьютекс, условные переменные расчитаны на его использование. Вызывать notify без лока разрешили не потому что он не нужен, а потому что вызов notify при активном локе ухудшает производительность.

xaizek ★★★★★ ()
Ответ на: комментарий от xaizek

не должно быть проблемой в общем случае

Касательно случаев использования полноценных блокировок вопросов нет - там всё нормально

Deleted ()
Ответ на: комментарий от Deleted

метод notify обязательно вызывать под той же захваченной блокировкой

В крестах такого требования нет(???)

Вот ответ на похожий вопрос: https://stackoverflow.com/questions/17101922/do-i-have-to-acquire-lock-before... .

не должно быть проблемой в общем случае

Касательно случаев использования полноценных блокировок вопросов нет - там всё нормально

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

aureliano15 ★★ ()
Ответ на: комментарий от anonymous

Я знал, что этот комментарий здесь будет) Со стандартными фьючерсами долгая история, запилить на их основе получается только с использованием больших костылей

Deleted ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.