Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/149.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 通知条件变量后使用互斥_C++_Mutex - Fatal编程技术网

C++ 通知条件变量后使用互斥

C++ 通知条件变量后使用互斥,c++,mutex,C++,Mutex,通知条件变量在收到通知后重新锁定互斥锁的原因是什么 如果unique_lock未限定作用域或互斥锁未明确解锁,则以下代码段会死锁 #include <future> #include <mutex> #include <iostream> using namespace std; int main() { std::mutex mtx; std::condition_variable cv; //simulate another

通知条件变量在收到通知后重新锁定互斥锁的原因是什么

如果unique_lock未限定作用域或互斥锁未明确解锁,则以下代码段会死锁

#include <future>
#include <mutex>
#include <iostream>

using namespace std;

int main()
{
    std::mutex mtx;
    std::condition_variable cv;

    //simulate another working thread sending notification
    auto as = std::async([&cv](){   std::this_thread::sleep_for(std::chrono::seconds(2));
                                    cv.notify_all();});

    //uncomment scoping (or unlock below) to prevent deadlock 
    //{

    std::unique_lock<std::mutex> lk(mtx);

    //Spurious Wake-Up Prevention not adressed in this short sample
    //UNLESS it is part of the answer / reason to lock again
    cv.wait(lk);

    //}

    std::cout << "CV notified\n" << std::flush;

    //uncomment unlock (or scoping  above) to prevent deadlock 
    //mtx.unlock();

    mtx.lock();
    //do something
    mtx.unlock();

    std::cout << "End may never be reached\n" << std::flush;

    return 0;
}
#包括
#包括
#包括
使用名称空间std;
int main()
{
std::互斥mtx;
std::条件变量cv;
//模拟另一个工作线程发送通知
自动as=std::async([&cv](){std::this_线程::sleep_for(std::chrono::seconds(2));
cv.notify_all();});
//取消注释范围(或下面的解锁)以防止死锁
//{
标准:唯一锁lk(mtx);
//本短样本中未涉及虚假唤醒预防
//除非这是再次锁定的答案/理由的一部分
cv.等待(lk);
//}

std::cout您尝试锁定互斥锁两次。一次是使用唯一的_锁,另一次是使用显式的
mutex.lock()
调用。对于非递归互斥锁,它将在重新锁定时死锁,以告知您有错误

std::unique_lock<std::mutex> lk(mtx);   // This locks for the lifetime of the unique_lock object

cv.wait(lk);  // this will unlock while waiting, but relock on return

std::cout << "CV notified\n" << std::flush;

mtx.lock();  // This attempts to lock the mutex again, but will deadlock since unique_lock has already invoked mutex.lock() in its constructor.
std::unique_lock lk(mtx);//此选项锁定unique_lock对象的生存期
cv.wait(lk);//这将在等待时解锁,但在返回时重新锁定

std::cout您尝试锁定互斥锁两次。一次是使用唯一的_锁,另一次是使用显式的
mutex.lock()
调用。对于非递归互斥锁,它将在重新锁定时死锁,以告知您有错误

std::unique_lock<std::mutex> lk(mtx);   // This locks for the lifetime of the unique_lock object

cv.wait(lk);  // this will unlock while waiting, but relock on return

std::cout << "CV notified\n" << std::flush;

mtx.lock();  // This attempts to lock the mutex again, but will deadlock since unique_lock has already invoked mutex.lock() in its constructor.
std::unique_lock lk(mtx);//此选项锁定unique_lock对象的生存期
cv.wait(lk);//这将在等待时解锁,但在返回时重新锁定

std::cout因为条件wait可能返回的原因除了被通知(如信号)之外,或者仅仅是因为其他人写入了相同的64字节缓存线。或者它可能已经被通知,但条件不再为真,因为另一个线程处理了它

因此,互斥锁被锁定,这样代码就可以在保持互斥锁的同时检查其条件变量。也许这只是一个布尔值,表示它已经准备就绪


不要跳过这一部分。如果你跳过了,你会后悔的。

因为等待条件可能返回的原因除了被通知之外,比如信号,或者仅仅是因为其他人写入了相同的64字节缓存线。或者它可能已经被通知,但条件不再是真的,因为另一个线程处理了它

因此,互斥锁被锁定,这样代码就可以在保持互斥锁的同时检查其条件变量。也许这只是一个布尔值,表示它已经准备就绪


不要跳过这一部分。如果你跳过了,你会后悔的。

让我们暂时想象一下,从
等待
返回时,
互斥锁未锁定:

线程1: 锁定互斥锁,检查谓词(无论是什么),并在发现谓词的形式不可接受时,等待其他某个线程将其置于可接受的形式。该等待会自动将线程1置于睡眠状态,并解锁
互斥体。解锁
互斥体后,其他某个线程将有权将谓词置于可接受状态(谓词自然不是线程安全的)

线程2: 同时,此线程正在尝试锁定
互斥体
,并将谓词置于线程1可以接受的状态,以使其继续通过等待。它必须在
互斥体
锁定的情况下执行此操作。
互斥体
防止谓词一次被多个线程访问(读或写)

一旦线程2将
互斥体
置于可接受的状态,它将通知
条件变量
,并解锁
互斥体
(这两个操作的顺序与此参数无关)

线程1: 现在线程1已经收到通知,我们假设
互斥锁在从
等待
返回时未被锁定。线程1必须做的第一件事是检查谓词,看看它是否确实可以接受(这可能是一个虚假的唤醒)。但它不应在未锁定
互斥体的情况下检查谓词。否则,其他线程可能会在该线程检查谓词后立即更改该谓词,从而使该检查的结果无效

因此,这个线程在唤醒时必须做的第一件事就是锁定
互斥锁,然后检查谓词

因此,在从
wait
返回时锁定
mutex
确实更方便。否则等待的线程将不得不在100%的时间内手动锁定它


让我们再看看线程1进入等待时发生的事件:我说过睡眠和解锁是原子发生的。这非常重要。想象一下,如果线程1必须手动解锁互斥锁,然后调用等待:在这个假设场景中,线程1可以解锁互斥锁,然后当另一个线程获得
互斥体时被中断,更改谓词,解锁
互斥体,并向
条件变量发出信号,所有这些都是在线程1调用
等待
之前发生的。现在线程1将永远休眠,因为没有线程会看到谓词需要更改,并且
条件变量需要更改需要信号


因此,
unlock
/enter-
wait
必须以原子方式进行。如果
lock
/exit-
wait
也以原子方式进行,则该API更易于使用。

让我们暂时设想一下,从
wait
返回时,
互斥锁未被锁定:

线程1: 锁定
mutex
,检查谓词(无论是什么),发现谓词的形式不可接受时,等待其他线程将其置于可接受的形式。等待会自动将线程1置于睡眠状态,并使用
m解锁
mutex