Wpis z mikrobloga

Cześć,

Zaimplementowałem kolejkę thread-safe, standardowo jeden thread do niej pisze, drugi czyta i parsuje dane. Kłopot polega na tym, że thread, który zapisuje czasami musi zbyt długo czekać na zwolnienie kolejki przez co są gubione porcje danych, bo blokowane jest odbieranie. Czy zapis do kolejki odebranej porcji danych powinienem puszczać w osobnych taskach, żeby nie blokować odbierania? Czy jest jakiś mądrzejszy sposób?

#programowanie #programista15k #cpp
  • 16
  • Odpowiedz
  • Otrzymuj powiadomienia
    o nowych komentarzach

  • 0
@zwei Kolejka składa się niestety z żywych bajtów, mutex jest blokowany na czas wyciągania pojedynczych bajtów aż zostanie uformowana pełna ramka.
  • Odpowiedz
@Parseval: a to już od mądrości implementującego zależy:D

przykład 1:
pisarz najpierw wpisuje dane, a potem przesuwa wskaźnika koniec kolejki
czytelnik najpierw odczytuje a potem przesuwa wskaźnik początku
  • Odpowiedz
@Parseval: chyba nie mówisz nam wszystkiego, co ten wątek "czytający" robi takiego, że to tyle trwa? Jakie dokładnie rzeczy trzymasz w tej kolejce? Możesz pokazać kod?
  • Odpowiedz
  • 0
@Saly Wątek czytający wyciąga bajt po bajcie z tej kolejki aż nie napotka początku i końca ramki. Jeśli jest pusta kolejka, to nie blokuje. Postaram się wstawić kawałek kodu jak będę przy komputerze.
  • Odpowiedz
@Parseval: brzmi źle. Przy takim designie nie bawiłbym się w wątki tylko zrobiłbym wszystko na jednym. Tworząc takie podejście z wątkami starałbym się to tak zaprojektować, żeby sekcja krytyczna była jak najmniejsza. Przykładowo wątek producent pchałby jakiś pakiet danych do jakiegoś std::vector i wsadzałby go do kolejki. Koszt: jak użyjesz std::move to kilka cykli procesora, wystarczy przepisać kilka liczb i wskaźnik. Wątek czytający bierze ten wektor z kolejki, kosz sekcji
  • Odpowiedz
@Saly W tym protokole niestety nie ma długości wiadomości :( Wtedy uniknąłbym kilku problemów, które napotkałem po drodze. Dzięki za porady, postaram się je dobrze zastosować.
  • Odpowiedz
@Parseval:
1. jak już wspomniano, przechowuj całe paczki bajtów, to będzie je łatwo wyekstrachować np. jezeli będą pod jakimś uniqueptr. myk robimy move na uniqueptr i jest cała paczka dostępna.

2. ten lock przy back() i front() to pchanie się w gips, robisz locka przy pobraniu adresu, a potem już droga wolna do modyfikacji konteneru przez kogokolwiek i zostajesz ze smieciowym adresem

3. te unique_locki bez std::locka afaik
  • Odpowiedz
@MamCieNaHita: Kurcze z tą paczką danych mam wątpliwości, bo odbieram paczki bajtów stałej długości gdzie długości ramki (od bajtu startowego do końcowego) są różne. Czyli będę mógł trafić paczkę gdzie ramka nie jest jeszcze skończona, wtedy muszę pobrać drugą paczkę gdzie koniec ramki jest w połowie, a reszta bajtów( zostając przy logice funkcji, która ma wyciągnąć taką ramkę) się straci.
  • Odpowiedz
bo odbieram paczki bajtów stałej długości


@Parseval: brzmi jak prosty std::unique_ptr>

a reszta bajtów( zostając przy logice funkcji, która ma wyciągnąć taką ramkę) się straci.


@Parseval: dokładasz adapter nad tą kolejką, który trzyma kolejkę, chunk i indeks w chunku. interfejsem adaptera będzie zwracanie pojedynczego bajtu, a pod spodem pobierasz chunk i zapamietujesz go, a następny pobierasz dopiero jak wypstrykasz się z bajtów w ostatnio pobranym
  • Odpowiedz