Синхронизируйте больше потоков с атомарной переменной

Я сейчас работаю над школьной проекцией, и у меня есть некоторые проблемы с синхронизацией 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;
}

-2

Решение

Я нашел время, чтобы исправить и предоставить обратную связь. Пожалуйста, не торопитесь, чтобы учиться и понимать. Я добавил комментарии в коде также.

  • Я убрал строку #include <string>, потому что нет strings используются в этой программе.
  • Я убрал строку 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 петли и все они следуют той же схеме:

  1. Получите блокировку, отпустите мьютекс и подождите, пока условие не станет истинным. Тем временем поток заблокирован.
  2. Обработайте данные и установите счетчик (условие для другого потока).
  3. Разблокируйте мьютекс и оповестите все ожидающие потоки (чтобы можно было разбудить следующий поток, условие которого выполнено).

И поэтому потоки могут выполняться по очереди.


#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;
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]