У меня есть код ниже. Это простой пример печати чередующихся чисел до 2N, используя 3 потока. Один печатает 0, другой печатает нечетные числа, а другой печатает четные. например, ввод 2 выходов 0102 на консоль. В настоящее время код работает, однако у меня есть вопрос только для моего понимания.
Например, в нечетной функции, если я изменю
while (!(print_zero == 0 && print_odd == 1)) {
cv.wait(lck);
}
на
//doesnt work
while (print_zero == 1 && print_odd == 0) {
cv.wait(lck);
}
Я больше не получаю последовательного правильного поведения, вместо этого иногда он заходит в тупик, иногда он печатает в необычном порядке. Но мне кажется, что это должно быть то же самое, и что логика c идентична. Кто-нибудь знает, почему это так?
#include <condition_variable>
#include <mutex>
#include <iostream>
#include <atomic>
using namespace std;
class ZeroEvenOdd {
private:
int n;
mutex mtx;
condition_variable cv;
int print_zero, print_even, print_odd;
public:
ZeroEvenOdd(int n) {
this->n = n;
print_zero = 1;
print_even = 0;
print_odd = 1;
}
void printNumber(int x) {
cout << x << endl;
}
// printNumber(x) outputs "x", where x is an integer.
void zero( ) {
for (int p = 0; p < n; p++) {
std::unique_lock<std::mutex> lck(mtx);
while (print_zero == 0) {
cv.wait(lck);
}
printNumber(0);
print_zero = 0;
cv.notify_all();
}
}
void even( ) {
//2
for (int j = 2; j <= n; j += 2) {
std::unique_lock<std::mutex> lck(mtx);
while (!(print_zero == 0 && print_even == 1)) {
cv.wait(lck);
}
printNumber(j);
print_zero = 1;
print_even = 0;
print_odd = 1;
cv.notify_all();
}
}
void odd() {
//3
for (int i = 1; i <= n; i += 2) {
std::unique_lock<std::mutex> lck(mtx);
//doesnt work
//while (print_zero == 1 && print_odd == 0) {
// cv.wait(lck);
//}
while (!(print_zero == 0 && print_odd == 1)) {
cv.wait(lck);
}
printNumber(i);
print_zero = 1;
print_even = 1;
print_odd = 0;
cv.notify_all();
}
}
};
int main()
{
std::cout << "Hello World!\n";
ZeroEvenOdd object(10);
std::thread t1(&ZeroEvenOdd::zero, &object);
std::thread t3(&ZeroEvenOdd::odd, &object);
std::thread t2(&ZeroEvenOdd::even, &object);
t1.join();
t2.join();
t3.join();
cout << "done" << endl;
}