多线程。两个不同线程中有两个 while 循环的未定义行为

Multi-thread. Undefined behaviour with two while loops in two different thread

#include <mutex>

using namespace std;

int counter = 0;
mutex m;

void thread1() {
    while(1) {
        m.lock();
        cout << "th1 " << counter << endl;
        ++counter;
        if (counter == 300) {
            m.unlock();
            break;
        }
        m.unlock();
    }
}

void thread2() {
    while(1) {
        m.lock();
        cout << "th2 " << counter << endl;
        if (counter == 10) {
            counter = 300;
            m.unlock();
            break;
        }
        m.unlock();
    }
}

int main(int argc, const char * argv[]) {

    thread th1(thread1);
    thread th2(thread2);
    th1.join();
    th2.join();
    return 0;
}

我是 运行 两个带 while 循环的线程。为什么尽管我使用 mutex lockunlock 这段代码的结果每次都不同。 来自函数 thread1 的第一个代码被执行了 X 次,然后来自函数 thread2 的代码被执行了 y 次。 他们不应该一个接一个地被执行吗.. thread1 -> thread2 -> thread1 -> 等等?

这是非确定性的,因为您有竞争条件。

每次解锁互斥量时,两个线程都会竞相再次锁定它。

同样在您的代码中,您可以递增超过 10 并错过线程 2 中的退出条件,这不是我认为您想要的。

您可以将执行同步为您描述的内容(thread1、thread2、thread1 等)的一种方法是使用条件变量 (std::condition_variable)。

这是您的代码,稍作修改以获得同步行为:

#include <mutex>
#include <iostream>
using namespace std;

int counter = 0;
bool flag = false;
mutex m;
condition_variable c;

void thread1() {
    while(1) {
        unique_lock<mutex> lk(m);
        c.wait(lk, []{ return flag; });
        cout << "th1 " << counter << endl;
        if (counter == 300) {
            flag=!flag;
            lk.unlock();
            c.notify_one();
            break;
        }
        counter++;
        flag=!flag;
        lk.unlock();
        c.notify_one();
    }
}

void thread2() {
    while(1) {
        unique_lock<mutex> lk(m);
        c.wait(lk, []{ return !flag; });
        cout << "th2 " << counter << endl;
        if (counter == 10) {
            counter = 300;
            flag=!flag;
            lk.unlock();
            c.notify_one();   
            break;
        }
        flag=!flag;
        lk.unlock();
        c.notify_one();
    }
}

int main(int argc, const char * argv[]) {

    thread th1(thread1);
    thread th2(thread2);
    th1.join();
    th2.join();
    return 0;
}

并且输出:

th2 0
th1 0
th2 1
th1 1
th2 2
th1 2
th2 3
th1 3
th2 4
th1 4
th2 5
th1 5
th2 6
th1 6
th2 7
th1 7
th2 8
th1 8
th2 9
th1 9
th2 10
th1 300

然后程序退出...

几个注意事项:

线程在 bool flag 变量上同步。

flag 用于创建在 conditional_variable

上调用的等待方法中使用的谓词
c.wait(lk, []{ return flag; });

这只是一个 lambda,returns 标志当前值。

th1 在 flag==true 上触发,th2 在 flag==false 上触发。

notify_one 方法告诉等待线程检查其条件。

并且我们使用了一个 unique_lock 实例,因为我们需要能够根据条件手动 lock/unlock 锁定。