Nie mam pojęcia na czym polega błąd, struktura w pewnym momencie zawiesza się problem rozwiązuje zastąpienie operacji std::condition_variable::wait na pętle
niedziałający kod plik queue_limited.h :
#pragma once
#include <iostream>
#include <memory>
#include <mutex>
#include <atomic>
#include <condition_variable>
template <typename T>
class queue_limited {
private:
struct node {
std::unique_ptr<node> next;
std::shared_ptr<T> data;
};
std::unique_ptr<node> head;
node* tail;
std::condition_variable push_condition;
std::condition_variable pop_condition;
std::atomic_uint max_size;
std::atomic_uint actual_size;
std::mutex head_mutex;
std::mutex tail_mutex;
public:
queue_limited(unsigned int);
void wait_and_push(const T&);
std::shared_ptr<T> wait_and_pop();
};
template <typename T>
queue_limited<T>::queue_limited(unsigned int _max_size) :
head(new node), tail(head.get()), max_size(_max_size), actual_size(0) {
}
template <typename T>
void queue_limited<T>::wait_and_push(const T& value) {
std::shared_ptr<T> temp_value = std::make_shared<T>(value);
std::unique_ptr<node> temp_node = std::make_unique<node>();
std::unique_lock<std::mutex> mutex_block(tail_mutex);
push_condition.wait(mutex_block, [&] {return actual_size < max_size; });
tail->data = std::move(temp_value);
tail->next = std::move(temp_node);
tail = tail->next.get();
actual_size++;
pop_condition.notify_one();
}
template <typename T>
std::shared_ptr<T> queue_limited<T>::wait_and_pop() {
std::unique_lock<std::mutex> mutex_block(head_mutex);
pop_condition.wait(mutex_block, [&] {return actual_size != 0; });
std::shared_ptr<T> temp_data = std::move(head->data);
head = std::move(head->next);
actual_size--;
push_condition.notify_one();
return temp_data;
}
działający kod plik queue_limited.h
#pragma once
#include <iostream>
#include <memory>
#include <mutex>
#include <atomic>
#include <condition_variable>
template <typename T>
class queue_limited {
private:
struct node {
std::unique_ptr<node> next;
std::shared_ptr<T> data;
};
std::unique_ptr<node> head;
node* tail;
std::condition_variable push_condition;
std::condition_variable pop_condition;
std::atomic_uint max_size;
std::atomic_uint actual_size;
std::mutex head_mutex;
std::mutex tail_mutex;
public:
queue_limited(unsigned int);
void wait_and_push(const T&);
std::shared_ptr<T> wait_and_pop();
};
template <typename T>
queue_limited<T>::queue_limited(unsigned int _max_size) :
head(new node), tail(head.get()), max_size(_max_size), actual_size(0) {
}
template <typename T>
void queue_limited<T>::wait_and_push(const T& value) {
std::shared_ptr<T> temp_value = std::make_shared<T>(value);
std::unique_ptr<node> temp_node = std::make_unique<node>();
std::unique_lock<std::mutex> mutex_block(tail_mutex);
while( actual_size >= max_size);
tail->data = std::move(temp_value);
tail->next = std::move(temp_node);
tail = tail->next.get();
actual_size++;
}
template <typename T>
std::shared_ptr<T> queue_limited<T>::wait_and_pop() {
std::unique_lock<std::mutex> mutex_block(head_mutex);
while(actual_size == 0);
std::shared_ptr<T> temp_data = std::move(head->data);
head = std::move(head->next);
actual_size--;
return temp_data;
}
plik.main.cpp
#include <iostream>
#include <thread>
#include <barrier>
#include "queue.h"
#include "queue_limited.h"
using namespace std;
queue_limited<int> temp(1);
barrier bariera(2);
void dodawanie() {
bariera.arrive_and_wait();
for (int i = 0; i < 50000; i++){
temp.wait_and_push(i);
}
}
void usuwanie() {
bariera.arrive_and_wait();
for (int i = 0; i < 50000; i++){
temp.wait_and_pop();
}
}
int main()
{
thread t1(dodawanie);
thread t2(usuwanie);
t1.join();
t2.join();
}