• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Współbieżna struktura danych

42 Warsaw Coding Academy
0 głosów
139 wizyt
pytanie zadane 2 września 2022 w C i C++ przez RufinB Bywalec (2,020 p.)

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();
}

 

1 odpowiedź

+1 głos
odpowiedź 3 września 2022 przez j23 Mędrzec (195,240 p.)
wybrane 3 września 2022 przez RufinB
 
Najlepsza

W poprzednim wątku pisałem Ci, że masz źle zrobioną synchronizację - synchronizujesz oddzielnie dodawanie i wyciąganie z kolejki. Zmienna warunkowa jedynie synchronizuje w momencie, gdy wait_and_push lub wait_and_pop nie może wykonać operacji (nie ma miejsca na nowy element lub kolejka jest pusta). Jeśli warunki do wykonania push i pop są spełnione - synchronizacji brak, a to zawsze kończy się problemami. Wystarczy synchronizować jednym wspólnym muteksem obie operacje i problem zniknie.

Podobne pytania

+2 głosów
0 odpowiedzi 147 wizyt
0 głosów
1 odpowiedź 165 wizyt
pytanie zadane 10 sierpnia 2022 w C i C++ przez RufinB Bywalec (2,020 p.)
0 głosów
0 odpowiedzi 153 wizyt

93,386 zapytań

142,385 odpowiedzi

322,547 komentarzy

62,748 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

VMware Cloud PRO - przenieś swoją infrastrukturę IT do chmury
...