2016-03-03 6 views
5

Я нашел следующий пример для переменной условия на www.cppreference.com, http://en.cppreference.com/w/cpp/thread/condition_variable. Вызов cv.notify_one() находится за пределами блокировки. Мой вопрос заключается в том, должен ли выполняться вызов, удерживая блокировку, чтобы гарантировать, что ожидающие потоки фактически находятся в состоянии ожидания и получат сигнал уведомления.C++ должен содержать переменную, которая должна быть уведомлена под блокировкой

#include <iostream> 
#include <string> 
#include <thread> 
#include <mutex> 
#include <condition_variable> 

std::mutex m; 
std::condition_variable cv; 
std::string data; 
bool ready = false; 
bool processed = false; 

void worker_thread() 
{ 
    // Wait until main() sends data 
    std::unique_lock<std::mutex> lk(m); 
    cv.wait(lk, []{return ready;}); 

    // after the wait, we own the lock. 
    std::cout << "Worker thread is processing data\n"; 
    data += " after processing"; 

    // Send data back to main() 
    processed = true; 
    std::cout << "Worker thread signals data processing completed\n"; 

    // Manual unlocking is done before notifying, to avoid waking up 
    // the waiting thread only to block again (see notify_one for details) 
    lk.unlock(); 
    cv.notify_one(); 
} 

int main() 
{ 
    std::thread worker(worker_thread); 

    data = "Example data"; 
    // send data to the worker thread 
    { 
     std::lock_guard<std::mutex> lk(m); 
     ready = true; 
     std::cout << "main() signals data ready for processing\n"; 
    } 
    cv.notify_one(); 

    // wait for the worker 
    { 
     std::unique_lock<std::mutex> lk(m); 
     cv.wait(lk, []{return processed;}); 
    } 
    std::cout << "Back in main(), data = " << data << '\n'; 

    worker.join(); 
} 

Если вызов notify_one() перемещается внутрь замка, чтобы гарантировать ожидающие потоки получать уведомления сигнал,

// send data to the worker thread 
{ 
    std::lock_guard<std::mutex> lk(m); 
    ready = true; 
    cv.notify_one(); 
    std::cout << "main() signals data ready for processing\n"; 
} 
+2

Будет ли [этот] (http://stackoverflow.com/a/17102100/1460794) ответить на ваш вопрос? – wally

+0

Возможный дубликат [Почему переменные функции состояния pthreads требуют мьютекса?] (Http://stackoverflow.com/questions/2763714/why-do-pthreads-condition-variable-functions-require-a-mutex) – wilx

+0

документация ответит на ваш вопрос явно, просто прочитайте! Для вас: блокировка не требуется для уведомления ... И сохранение мьютекса не гарантирует, что поток находится в состоянии ожидания. – knivil

ответ

4

, если я правильно понимаю ваш вопрос, это equivilant к «должен уведомитель нить блокировать мьютексы при попытке уведомить о каком-то CV в другой теме »

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

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

+0

Есть ли гонка, которая приведет к отсутствию сигнала, если блокировка не удерживается при вызове 'notify_one()'? – Slava

+0

общие мьютексы и condition_variables не могут вызывать состояние гонки внутри себя, это примитивы синхронизации. –

+0

@Slava Да, вы можете пропустить сигналы, но вы можете пропустить сигналы, если он тоже удерживает блокировку - хотя ваш код кажется безопасным из-за этого из-за 'cv.wait (lk, [] {return ready;})', независимо от того, что notify_one() выполняется с заблокированной фиксацией или нет. (Но установка готового флага должна быть выполнена с заблокированной фиксацией) – nos

-1

Если вы не ждете от переменной условия, тогда уведомление будет потеряно. Неважно, если вы держите замки. Переменная состояния - это примитив синхронизации и не требует блокировки для защиты.

Вы можете пропустить сигналы с блокировкой и без нее. Мьютекс защищает только обычные данные, такие как ready или processed.

+0

К сожалению, все могут голосовать правильно. – knivil

+0

Этот пользователь глубоко смущен. – SergeyA

6

Вам не нужно уведомлять об этом под замком. Однако, поскольку уведомление происходит логически, когда изменяется фактическое значение (в противном случае, почему вы уведомляете?), И это изменение должно быть происходит под замком, это часто делается в пределах блокировки.

Не было бы практической наблюдаемой разницы.

+0

В этом конкретном коде может не быть разницы, но он есть вообще, я уже размещал ссылки – Slava

+0

@Slava, вы разместили ссылки на свои собственные ответы. Это вряд ли авторитет, извините. Я поддерживаю свои заявления. Не будет никакой гонки при правильном использовании (то есть, блокировка перед проверкой и блокировкой перед настройкой) – SergeyA

+0

Я разместил ссылку на один из моих ответов и один не мой, прочитал второй, если вы предпочитаете – Slava