通知所有在多线程C++不起作用.导致死锁

notifyall not working in C++ multithreading . Causing deadlock

本文关键字:不起作用 死锁 C++ 多线程 通知      更新时间:2023-10-16
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
using namespace std;
int num = 1;
#define NUM 20
condition_variable odd;
condition_variable even;
mutex mut;
void thread_odd()
{
        while(num < NUM -1)
        {
            if(num%2 != 1)
            {
                  unique_lock<mutex> lock(mut);
                  odd.wait(lock);
            }
            cout<<"ODD : "<<num<<endl;
            num++;
            even.notify_all();  // Line X
        }
}
void thread_even()
{
        while(num < NUM )
        {
            if(num%2 != 0)
            {
                  unique_lock<mutex> lock(mut);
                  even.wait(lock);
            }
            cout<<"EVEN : "<<num<<endl;
            num++;
            odd.notify_all();
        }
}
int main()
{
       thread t1(thread_odd), t2(thread_even);
       t1.join();
       t2.join();
       return 0;
}

/* 以上是以同步方式(一个接一个(打印 ODD 和偶数的程序。代码大部分时间都工作正常。 但它有时会陷入僵局。 当奇数线程击中notify_all时就会发生这种情况,但在偶数线程唤醒之前,奇数线程获取锁,然后当它发现等待条件时,它会进入等待状态,而偶数线程尚未唤醒。 留下一个聋子的情况.我尝试将notify_all替换为notify_one, 但问题仍然存在.是否需要对设计进行任何更改? 还是我完全缺少了什么?*/

作为并发程序中的一般规则,当您想要访问共享资源以读取和修改它时(在您的情况下,num 上的模运算符是第一次读取,num++ 是写入(,您需要获得对该资源的相互独占访问权限,并且在完成该资源之前不要释放它

当 if 语句作用域存在锁时,您的锁将被释放,因此您不遵循此规则。

如果按如下方式修改代码,则不会死锁:

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
using namespace std;
int num = 1;
#define NUM 20
condition_variable odd;
condition_variable even;
mutex mut;
void thread_odd()
{
    while(num < NUM -1)
    {
        unique_lock<mutex> lock(mut);
        if(num%2 != 1)
        {
            odd.wait(lock);
        }
        cout<<"ODD : "<<num<<endl;
        num++;
        lock.unlock();
        even.notify_all();  // Line X
    }
}
void thread_even()
{
    while(num < NUM )
    {
        unique_lock<mutex> lock(mut);
        if(num%2 != 0)
        {
            even.wait(lock);
        }
        cout<<"EVEN : "<<num<<endl;
        num++;
        lock.unlock();
        odd.notify_all();
    }
}
int main()
{
    thread t1(thread_odd), t2(thread_even);
    t1.join();
    t2.join();
    return 0;
}

请注意我在通知之前是如何释放锁的。在C++中,这不仅是可能的(与Java相反(,而且建议这样做,因为您将减少释放者贪婪地重新进入关键块的机会。您将在此处获得有关最后一点的更多见解。