I am working on a programming task that takes in an n
value and uses three threads to print zero, even and odd numbers.
For example, if n = 3
, it will print 010203
. I encountered a strange behavior that when rvalue is used in the condition check in a for loop, my program just hangs entirely without doing anything. This phenomenon only appears in multithreading program. Thus, I put the entire code here:
#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;
}
The above program can be compiled and run with g++ 1116.cpp -std=c++11 -pthread -O0 && ./a.out
, but the program just hangs without doing anything. However, if I change the lines
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
to
for (int a = 2; a <= ((this->n) + 0); a += 2) {
for (int b = 1; b <= ((this->n) + 0); b += 2) {
then everything works as expected.
I've tried to reproduce this phenomenon in single thread program, but this behavior doesn't present in single thread program.
I am not sure if this behavior has anything to do with multithreading. I just provide every evidence I have for people to investigate.
Update: Change typo lvalue
to rvalue
.
Although locking and unlocking of the mutexes in different threads is an issue, it is not the issue.
When the loop control is <= ((this->n) + 1), the program proceeds as follows:
threadB never exits and waits for ever because (a += 2) == 4 and ((this->n) + 1) == 4.
Nothing is emitted because the output remains buffered.