C++:条件变量-这个youtube演示中有错误吗

C++: Condition Variable - Is there a mistake in this youtube demo?

本文关键字:有错误 youtube 这个 条件 变量 C++      更新时间:2024-03-29

Youtube详细信息

我一直在浏览youtube,试图发展我对C++多线程支持互斥和条件变量的理解。

我偶然看到这个视频跳到时间6:30查看我当前正在查看的内容。(一页代码。(

  • https://www.youtube.com/watch?v=eh_9zUNmTig

我相信代码中有一个错误,但我想检查一下。也可能是我什么都不懂。

问题

作者指出std::unique_lock在创建互斥锁时会锁定互斥锁。这意味着没有必要调用

unique_lock<mutex> lock(m)
lock.lock(); // this is wrong, because unique_lock already locked the mutex

在创建CCD_ 2对象之后。

假设,尽管我不确定,unique_lock将在销毁时释放互斥锁。(超出范围时为阿卡。(


也可以通过调用手动解锁吗

lock.unlock()

从文档中看,似乎没有这样的解锁功能。因此看起来unique_lockscoped_lock是一样的?但是,我再次假设事实并非如此,我还缺少一些其他信息。


继续作者有一个函数,看起来像这样:

void addMoney(int money)
{
std::lock_guard<mutex> lg(m); // lock_guard being used interchangably with unique_lock - why?
balance += money; // adding to global variable
cv.notify_one(); // error here
// the lock_guard is still in scope
// the mutex is still locked
// calling notify_one() may cause the sleeping thread to wake up
// check if the mutex is still locked (which it might be if the
// destructor for lg hasn't finished running)
// and then go back to sleep
// meaning this line of code may have no effect
// it is undefined behaviour
}

我已经说明了我认为哪里有错误。我认为这个函数会导致未定义的行为,因为lock_guard仍然在作用域中,因此互斥可能被锁定。

实际上这是一个竞赛条件:

  • 如果addMoney()在其他函数开始之前结束,我们就可以了
  • 如果另一个函数withdrawMoney()addMoney()退出之前检查锁定(cv.wait()(,则程序中断,并保持锁定状态

为了完整性,这里有另一个函数:

void withdrawMoney(int money)
{
std::unique_lock<mutex> ul(m); // unique_lock instead of scoped_lock? why?
cv.wait(ul, []{return balance != 0;});
// some more stuff omitted
}

摘要

我提出了几点

  • 最重要的是比赛条件
  • 次要的是,为什么两个不同的东西(lock_guardunique_lock(被用来做看起来的事情(执行相同的功能(

该注释

// calling notify_one() may cause the sleeping thread to wake up
// check if the mutex is still locked (which it might be if the
// destructor for lg hasn't finished running)
// and then go back to sleep

不正确。这里有两种独立的控制机制:条件变量和互斥。在一个条件变量的通知中醒来,简单地说,就是醒来。唤醒后,线程阻塞等待互斥。当调用notify_one()的线程释放互斥体时,被阻塞的线程(或者可能是其他线程,但最终是被阻塞的螺纹(获得互斥体并继续执行。它不会返回到等待条件变量。

有关std::unique_lock与std::lock_guard的更多解释,请参阅此问题。

在互斥锁仍然被锁定的情况下发送通知时没有未定义的行为。它可能会导致不必要的线程切换,尤其是在接收线程具有更高优先级的情况下,但这只是一个小的性能打击。也不需要锁定互斥来发送通知,因此函数可以写成:

void addMoney(int money)
{
{
std::lock_guard<mutex> lg(m);
balance += money;
}
cv.notify_one();
}

您必须确保条件的资源在更改和检查时受到保护。