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

Współbieżna struktura danych

Object Storage Arubacloud
0 głosów
103 wizyt
pytanie zadane 2 września 2022 w C i C++ przez RufinB Obywatel (1,830 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 (194,920 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

0 głosów
1 odpowiedź 110 wizyt
pytanie zadane 10 sierpnia 2022 w C i C++ przez RufinB Obywatel (1,830 p.)
0 głosów
0 odpowiedzi 117 wizyt
0 głosów
1 odpowiedź 297 wizyt

92,547 zapytań

141,389 odpowiedzi

319,508 komentarzy

61,931 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.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...