多线程。两个不同线程中有两个 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
lock
和 unlock
这段代码的结果每次都不同。
来自函数 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 锁定。
#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
lock
和 unlock
这段代码的结果每次都不同。
来自函数 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 锁定。