многопоточность — в простой программе C ++ 11 с четырьмя потоками мои два пользовательских потока не возвращаются, если я комментирую строки вывода stdout

Я изучаю свой путь через примитивы синхронизации с C ++ 11. Я должен написать эти методы для шаблонного класса, который является очередью FIFO, максимальное количество элементов которого объявлено во время построения.

Есть два потока, которые помещают элементы в указанную очередь, и два, которые получают их. Они синхронизируются с помощью двух условных переменных, чтобы убедиться, что потребительские потоки извлекают элементы только тогда, когда очередь не пуста, а потоки-производители выдвигают новые элементы только тогда, когда очередь не заполнена. Очередь имеет статус открытия / закрытия, который используется как дополнительное условие в вызове wait () обеих переменных условия. Когда очередь закрыта, потоки должны вернуться без выполнения каких-либо операций.

// main.cpp
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[]){
BlockingQueue<int> bq(10);
int sum1=0, sum2=0;

std::thread c1([&bq,&sum1](){
int i;
while(bq.get(i)) sum1+=i;
});
std::thread c2([&bq,&sum2](){
int i;
while(bq.get(i)) sum2+=i;
});
std::thread p1([&bq](){
for(int i=0;i<1000;i+=2) bq.put(i);
});
std::thread p2([&bq](){
for(int i=0;i<1000;i+=2) bq.put(i+1);
});
p1.join();
std::cout<<"p1 thread returned."<<std::endl;
p2.join();
std::cout<<"p2 thread returned."<<std::endl;
bq.close();
c1.join();
std::cout<<"c1 thread returned."<<std::endl;
c2.join();
std::cout<<"c2 thread returned."<<std::endl;
std::cout<<"sum1: "<<sum1<<std::endl;
std::cout<<"sum2: "<<sum2<<std::endl;
std::cout<<"total: "<<sum1+sum2<<std::endl;
return 0;
}

Вот класс, который я создал:

// BlockingQueue.h
#include "stdafx.h"
template<class T> class BlockingQueue
{
std::mutex t_queue_mutex;
std::queue<T> t_queue;
int t_queue_cap_value;
bool isQueueOpen;
std::condition_variable put_condition;
std::condition_variable get_condition;
public:
BlockingQueue(int N);
~BlockingQueue(void);
bool put(T t_item);
bool get(T &t_item);
bool isOpen();
bool isFull();
bool isEmpty();
void close();
};

// BlockinQueue.cpp
#include "BlockingQueue.h"#include "stdafx.h"
template <class T> BlockingQueue<T>::BlockingQueue(int N)
{
t_queue_cap_value=N;
isQueueOpen=true;
std::cout<<"Rejoice! A bq has been created!"<<std::endl;
}

template <class T> BlockingQueue<T>::~BlockingQueue(void)
{
}

template <class T> bool BlockingQueue<T>::isFull(){
if(t_queue_cap_value==t_queue.size())
return true;
else
return false;
}

template <class T> bool BlockingQueue<T>::isOpen(){
return isQueueOpen;
}

template <class T> void BlockingQueue<T>::close(){
isQueueOpen=false;
}

/* get method */
template <class T> bool BlockingQueue<T>::get(T &t_item){
bool exitThreadStatus=false;

if(!isOpen()){
put_condition.notify_all();
return false;
}
std::unique_lock<std::mutex> ul(t_queue_mutex);
get_condition.wait(ul, [this](){
//std::cout<<"Getter thread with get_id()="<<std::this_thread::get_id()<<" is waiting. isOpen()="<<isOpen()<<" and t_queue.empty()="<<t_queue.empty()<<std::endl;
if(!isOpen())
return true;
else
return !t_queue.empty();
});
if(isOpen()){
exitThreadStatus=true;
t_item=t_queue.front();
t_queue.pop();
}
std::cout<<"Extracted "<<t_item<<". After pop size()="<<t_queue.size()<<std::endl;
put_condition.notify_all();
return exitThreadStatus;
}

/* put method */
template <class T> bool BlockingQueue<T>::put(T t_item){
bool exitThreadStatus=false;

if(!isOpen()){
get_condition.notify_all();
return false;
}
std::unique_lock<std::mutex> ul(t_queue_mutex);
put_condition.wait(ul, [this](){
if(!isOpen())
return true;
else
return !isFull();
});
if(isOpen()){
exitThreadStatus=true;
t_queue.push(t_item);
}
std::cout<<"Inserting "<<t_item<<". After push size()="<<t_queue.size()<<std::endl;
get_condition.notify_all();
return exitThreadStatus;
}

template class BlockingQueue<int>;

Кажется, он работает правильно, когда я оставляю две строки std :: cout в get () и put () без комментариев, получая следующий результат (как и ожидалось):

Inserting 998. After push size()=2
Extracted 997. After pop size()=1
p1 thread returned.
Inserting 999. After push size()=2
Extracted 998. After pop size()=1
p2 thread returned.
Extracted 999. After pop size()=0
Extracted 998. After pop size()=0
c1 thread returned.
c2 thread returned.
sum1: 250000
sum2: 249500
total: 499500

Если я вместо этого прокомментирую строки cout, два потока сбора никогда не возвращаются, и я не могу понять, что не так с моим кодом. У кого-нибудь есть ключ? Спасибо!

Вывод с закомментированными строками:

Rejoice! A bq has been created!
p1 thread returned.
p2 thread returned.

1

Решение

Попробуйте добавить get_condition.notify_all () и put_condition.notify_all (), чтобы закрыть ().

Насколько я могу судить, если поток находится в get_condition.wait () внутри get () при вызове close (), он остается в этом ожидании вечно. Почему это работает с утверждениями cout, я понятия не имею, хотя в документации упоминаются «ложные пробуждения».

3

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

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

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector