Я сейчас работаю над школьной проекцией, и у меня есть некоторые проблемы с синхронизацией 3 потоков (2 потока + поток mian). В описании сказано, что я должен напечатать 100x «ping», затем 100x «pong» и 100x «\ n», НО в следующем порядке:
PingPong \ n и так далее …
когда я запускаю свой код, как у меня сейчас, он просто печатает 100xPing, затем 100xPong, а затем 100x \ n, и я не могу понять, почему 🙁
Точка, которую я не могу понять, должна остановиться, когда я установлю счетчик в 1, и она должна открыть cond.wait (); после этого он должен перейти в pong () и так далее …
Вот код:
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <atomic>
using namespace std;
mutex m; // Mutex
// Bedingungsvariable
condition_variable cond;
atomic<int> counter = 0;
bool done= true;
void ping() {
unique_lock <mutex > lock{ m }; // m sperren
while (counter != 0) {
cond.wait(lock); //sperren und dann wieder freigeben
}
while (counter == 0) {
for (int i = 0; i < 100; i++) {
cout << "Ping";
counter = 1;
cond.notify_one();
}
}
}
void pong() {
unique_lock <mutex > lock{ m }; // m sperren
while (counter != 1) {
cond.wait(lock);
}
while (counter == 1) {
for (int i = 0; i < 100; i++) {
cout << "Pong";
counter = 2;
cond.notify_one();
}
}
}int main() {
thread t1(pong);
thread t(ping); // Zweiten Thread starten
unique_lock <mutex > lock{ m }; // m sperren
while (counter != 2) cond.wait(lock);
while (counter == 2) {
for (int i = 0; i < 100; i++) {
cout << "\n";
counter = 0;
cond.notify_one();
}
}
lock.unlock(); // Mutex freigeben
t.join();
t1.join();
system("PAUSE");
return EXIT_SUCCESS;
}
Я нашел время, чтобы исправить и предоставить обратную связь. Пожалуйста, не торопитесь, чтобы учиться и понимать. Я добавил комментарии в коде также.
#include <string>
, потому что нет string
s используются в этой программе.bool done = true;
, Я не думаю, что вам это нужно.#include <condition_variable>
если вы хотите использовать условные переменные (Bedingungsvariablen).atomic<int> counter = 0;
выдает ошибку (g ++ 4.8.4, Ubuntu, флаг C ++ 11 включен). Вместо этого я заменил эту строку на atomic<int> counter{0};
,cond.wait(*lock*, *lambda*);
может выглядеть странно, но это так же, как while(*condition*) cond.wait(*lock*);
твой.notify_one()
уведомляет только один поток, но вы не можете контролировать, какой из них будет пробужден. Поэтому (так как у вас более двух потоков) я использую notify_all()
,system("PAUSE")
, Не нужно.Резюме (из механизма синхронизации):
В основном каждое значение счетчика (0, 1, 2) соответствует потоку (я думаю, что вы поняли эту идею правильно).
Однако вы пропустите while
циклы, потому что вы хотите зациклить / обработать только сто раз; вам просто нужно повторить сотню раз.
Так что лучше всего синхронизировать for
петли и все они следуют той же схеме:
И поэтому потоки могут выполняться по очереди.
#include <iostream>
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
using namespace std;
mutex m; // Mutex
condition_variable cond; // Bedingungsvariable
atomic<int> counter{0};
void ping() {
for (int i = 0; i < 100; i++) {
//cout << "Ping: m sperren und warten" << endl;
// m sperren und ...
unique_lock <mutex > lock{m};
//... dann wieder freigeben
//sobald counter == 0 gilt
cond.wait(lock, [] {
return counter == 0;
});
//Datenverarbeitung und ...
//... counter setzen für nächsten Thread
cout << "Ping";
counter = 1;
//cout << "Ping: m freigeben und benachrichtigen" << endl;
//m freigeben und
//andere Threads benachrichtigen
lock.unlock();
cond.notify_all();
}
}
void pong() {
for (int i = 0; i < 100; i++) {
//cout << "Pong: m sperren und warten" << endl;
//m sperren und ...
unique_lock <mutex > lock{m};
//... dann wieder freigeben
//sobald counter == 1 gilt
cond.wait(lock, [] {
return counter == 1;
});
//Datenverarbeitung und ...
//... counter setzen für nächsten Thread
cout << "Pong";
counter = 2;
//cout << "Pong: m freigeben und benachrichtigen" << endl;
//m freigeben und
//andere Threads benachrichtigen
lock.unlock();
cond.notify_all();
}
}
int main() {
thread t(ping); // ping Thread starten
thread t1(pong); // pong Thread starten
for (int i = 0; i < 100; i++) {
//cout << "\\n: m sperren und warten" << endl;
// m sperren und ...
unique_lock <mutex > lock{m};
//... dann wieder freigeben
//sobald counter == 2 gilt
cond.wait(lock, [] {
return counter == 2;
});
//Datenverarbeitung und ...
//... counter setzen für nächsten Thread
cout << endl;
counter = 0;
//cout << "\\n: m freigeben und benachrichtigen" << endl;
//m freigeben und
//andere Threads benachrichtigen
lock.unlock();
cond.notify_all();
}
t.join();
t1.join();
return EXIT_SUCCESS;
}
Примечание 1:
Это не работает:
atomic<int> counter = 0;
Это работает:
atomic<int> counter(0);
или же
atomic<int> counter{0};
или же
atomic<int> counter;
...
counter = 0;
Других решений пока нет …