我正在执行一项编程任务,该任务接受
n
值并使用三个线程打印 zero、even 和 odd 数字。
例如,如果
n = 3
,则会打印010203
。我遇到了一个奇怪的行为,当在 for 循环的条件检查中使用右值时,我的程序完全挂起而不执行任何操作。这种现象只出现在多线程程序中。因此,我将整个代码放在这里:
#include <functional> // function
#include <iostream>
#include <mutex> // mutex
#include <thread> // thread
using namespace std;
class ZeroEvenOdd {
private:
int n;
mutex zero_mtx, even_mtx, odd_mtx;
public:
ZeroEvenOdd(int n) {
this->n = n;
zero_mtx.unlock();
even_mtx.lock();
odd_mtx.lock();
}
// printNumber(x) outputs "x", where x is an integer.
void zero(function<void(int)> printNumber) {
for (int i = 1; i <= this->n; ++i) {
zero_mtx.lock();
printNumber(0);
if (i & 1) { // odd
odd_mtx.unlock();
} else { // even
even_mtx.unlock();
}
}
}
void even(function<void(int)> printNumber) {
for (int a = 2; a <= ((this->n) + 1); a += 2) { // NOTE: `(this->n) + 1` is an rvalue
even_mtx.lock();
printNumber(a);
zero_mtx.unlock();
}
}
void odd(function<void(int)> printNumber) {
for (int b = 1; b <= ((this->n) + 1); b += 2) { // NOTE: `(this->n) + 1` is an rvalue
odd_mtx.lock();
printNumber(b);
zero_mtx.unlock();
}
}
};
// g++ 1116.cpp -std=c++11 -pthread -O0 && ./a.out
int main() {
printf("helloworld\n");
ZeroEvenOdd zod(3);
auto printNumber = [](int x) { cout << x; };
thread threadA([&]() { zod.zero(printNumber); });
thread threadB([&]() { zod.even(printNumber); });
thread threadC([&]() { zod.odd(printNumber); });
threadA.join();
threadB.join();
threadC.join();
return 0;
}
上面的程序可以用
g++ 1116.cpp -std=c++11 -pthread -O0 && ./a.out
编译并运行,但是程序只是挂起而不做任何事情。但是,如果我改变线路
for (int a = 2; a <= ((this->n) + 1); a += 2) { // NOTE: `(this->n) + 1` is an rvalue
for (int b = 1; b <= ((this->n) + 1); b += 2) { // NOTE: `(this->n) + 1` is an rvalue
到
for (int a = 2; a <= ((this->n) + 0); a += 2) {
for (int b = 1; b <= ((this->n) + 0); b += 2) {
然后一切都按预期进行。
我尝试在单线程程序中重现这种现象,但这种行为在单线程程序中不存在。
我不确定这种行为是否与多线程有关。我只是提供我所拥有的所有证据供人们调查。
更新: 将拼写错误
lvalue
更改为 rvalue
。
虽然不同线程中互斥体的锁定和解锁是an问题,但它不是the问题。
当循环控制为<= ((this->n)+1)时,程序进行如下:
threadB 永远不会退出并永远等待,因为 (a += 2) == 4 且 ((this->n) + 1) == 4。
不会发出任何内容,因为输出仍处于缓冲状态。