Я пытаюсь напечатать 1,2,3,4,5,6,7, ..... но четные и нечетные числа из двух разных потоков. Также я хочу сделать эту программу, используя условные переменные. Я создал следующую программу, она просто распечатывает лишние части и зависает (может быть тупик .. я не знаю). Подскажите, пожалуйста, в чем проблема в моей реализации.
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
#define MAX 25
using namespace std;
mutex mu;
condition_variable cv;
void printodd()
{
for (size_t i = 0; i < MAX; i++)
{
if (i % 2 != 0)
{
unique_lock<mutex> locker(mu);
cout <<"Odd : "<< i << endl;
locker.unlock();
cv.notify_one();
}
}
}
void printeven()
{
for (size_t i = 0; i < MAX; i++)
{
if (i % 2 == 0)
{
unique_lock<mutex> locker(mu);
cv.wait(locker);
cout <<"Even : "<< i << endl;
locker.unlock();
}
}
}
int main()
{
thread th1(printodd);
thread th2(printeven);
th1.join();
th2.join();
getchar();
}
3 ответа
Потому что уведомления не ставятся в очередь. Это означает, что если вызывается notify_one()
и в настоящее время нет ожидающих потоков, это уведомление просто теряется. Вы видите 1,2,3,4,5,6,7,.....
, потому что первый поток завершился даже быстрее, чем запустился второй поток. После запуска второго потока он немедленно переходит в режим ожидания, который длится вечно (тупик).
Более того, даже если уведомления были поставлены в очередь (гипотетически), вы сначала увидите 1
из первого потока и только 0
из второго потока (после того, как он получил бы уведомление).
Вам нужно создать два мьютекса / условных переменных (по одному на каждый поток) и вызвать самое первое уведомление из основного потока.
Вам понадобятся две условные переменные: одна для нечетных чисел и одна для четных.
Каждый поток должен ждать своего собственного условия, как только оно станет доступным, распечатать его собственное следующее число, затем уведомить другой поток через эту переменную условия и ждать, пока другой поток снова не разблокирует его, как только он выполнит свою работу.
Чтобы начать работу, "нечетная" условная переменная должна быть уведомлена один раз после создания потоков для печати первой "единицы".
Я согласен с другими ответами в их анализе причины проблемы (отсутствие очереди уведомлений), но не согласен с тем, что требуются два экземпляра объектов синхронизации.
Ваша проблема - одна из очереди производитель-потребитель, где производитель и потребитель чередуются на каждой итерации. Для очереди потребителя производителя достаточно одного мьютекса и условия. Следующие небольшие изменения в вашем коде заставят его работать:
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
#define MAX 25
using namespace std;
mutex mu;
condition_variable cv;
bool even = true;
void print_it(int k)
{
const auto is_even = k % 2 == 0;
for (size_t i = 0; i < MAX; i++)
{
if (i % 2 == k)
{
unique_lock<mutex> locker(mu);
cv.wait(locker, [is_even](){return even == is_even;});
cout <<": "<< i << endl;
even = !even;
locker.unlock();
cv.notify_one();
}
}
}
int main()
{
thread th0(print_it, 0);
thread th1(print_it, 1);
th0.join();
th1.join();
}
Похожие вопросы
Новые вопросы
multithreading
Для вопросов, касающихся многопоточности, способность компьютера или программы выполнять работу одновременно или асинхронно, используя несколько одновременных потоков выполнения (обычно называемых потоками).