C ++ kø i fast størrelse full / tom signalering

Jeg vurderer et program der store data må skrives til filen ofte. Jeg vil gjerne bruke en kø og har en produsent og forbruker som kjører på forskjellige tråder. I tillegg vil jeg ha en kø i fast størrelse, da datastørrelsen kan være veldig stor. Jeg har implementert en enkel test av boost :: lockfree :: kø med boost :: condition_variable for å signalisere køens tilstand. Jeg vil unngå mutex, men med unntak der køen er full (blokkprodusent) eller tom (blokk forbruker)

vil jeg vite (med risiko for meningsbasert ..) om jeg » m bruker betingelsene på riktig måte eller hvis det er et ytelsesproblem – sammenlignet med å bruke andre metoder. Dette er hva jeg har gjort så langt (små data)

#include <iostream> #include <boost/thread/thread.hpp> #include <boost/lockfree/queue.hpp> #define N 6 #define QN 3 struct testdata { int a; int b; }; boost::lockfree::queue<testdata, boost::lockfree::fixed_size<true>> que(QN); boost::condition_variable que_has_data, que_has_room; boost::mutex que_mtx_hd, que_mtx_hr; void producer(void) { testdata td; int i = 0; boost::mutex::scoped_lock lock(que_mtx_hr); boost::this_thread::sleep(boost::posix_time::seconds(1)); for (;;) { td.a = i; td.b = i + 1; if (!que.push(td)) { std::cout << "producer waiting" << std::endl; que_has_room.wait(lock); } else { std::cout << "pushed " << td.a << std::endl; i += 1; que.has_data_notify_one(); } if (i > N) break; } } void consumer(void) { testdata td; boost::mutex::scoped_lock lock(que_mtx_hd); for (;;) { if (que.pop(td)) { std::cout << "popped " << td.a << std::endl; if (td.a == N) break; que_has_room.notify_one(); } else { std::cout << "consumer waiting" << std::endl; que_has_data.wait(lock); } } boost::this_thread::sleep(boost::posix_time::seconds(1)); } int main(void) { boost::thread t1(&producer); boost::thread t2(&consumer); t1.join(); t2.join(); return 0; } 

Dette fungerer (utdata):

consumer waiting pushed 0 pushed 1 pushed 2 producer waiting popped 0 pushed 3 producer waiting popped 1 pushed 4 producer waiting popped 2 pushed 5 producer waiting popped 3 pushed 6 popped 4 popped 5 popped 6 

Jeg forventer at data for det meste nesten alltid vil være tilgjengelig, men jeg vil blokkere i tilfelle overbelastning ( filskriving, nettverk osv.). Interessen for fast størrelse er bekymringen for massive datasett og dynamisk tildeling i køen –

(Dette er mer et eksperiment på hva som kan gjøres. I virkeligheten oppdateres dataene mine maksimalt ca 20 Hz så bare å ta en lås på en std :: kø som jeg klarer størrelsen på, vil også fungere veldig bra.)

Svar

Bruk en semafor for å få produsentene til å sove når køen er full, og en annen semafor for å få forbrukerne til å sove når køen er tom. når køen verken er full eller tom, er sem_post og sem_wait-operasjonene ikke blokkerende (i nyere kjerner)

#include <semaphore.h> template<typename lock_free_container> class blocking_lock_free { public: lock_free_queue_semaphore(size_t n) : container(n) { sem_init(&pop_semaphore, 0, 0); sem_init(&push_semaphore, 0, n); } ~lock_free_queue_semaphore() { sem_destroy(&pop_semaphore); sem_destroy(&push_semaphore); } bool push(const lock_free_container::value_type& v) { sem_wait(&push_semaphore); bool ret = container::bounded_push(v); ASSERT(ret); if (ret) sem_post(&pop_semaphore); else sem_post(&push_semaphore); // shouldn"t happen return ret; } bool pop(lock_free_container::value_type& v) { sem_wait(&pop_semaphore); bool ret = container::pop(v); ASSERT(ret); if (ret) sem_post(&push_semaphore); else sem_post(&pop_semaphore); // shouldn"t happen return ret; } private: lock_free_container container; sem_t pop_semaphore; sem_t push_semaphore; }; 

Svar

Jeg ville være veldig skeptisk til koden som inneholder en låsfri beholder, to mutexer og en betinget variabel for å implementere blokkeringskø for interthread. Uten å se lenger.

Jeg vil sannsynligvis starte fra prototypen nedenfor (kanskje først sjekke om boost :: interprocess har noe jeg kan bruke med en gang):

  1. wrap boost::circular_buffer til facebook/Folly/Synchronized men med tilpasset skap som gjør try_lock(), og deretter spinner 41 ganger til med try_lock(), blokkerer deretter lock(), teller forekomster av alle tre scenariene, og med varsle / vent på toppen
  2. Jeg vil slippe det til produksjon i pilotmodus og sjekke om jeg virkelig trenger å bry meg med en låsfri container.

Kommentarer

  • Jeg ‘ følger ikke pseudokoden din veldig bra, men jeg forstår bekymringene du har. Jeg hadde regnet med at bruk av scoped_lock ville gjøre dette ok, og at hver krever det ‘ s mutex for den betingede ventetiden.

Svar

Boost gir en enkeltprodusent kø for én forbruker som er låsefri tror jeg, vet du om det? Jeg synes det passer din brukstilfelle nøyaktig.

http://www.boost.org/doc/libs/1_61_0/doc/html/boost/lockfree/spsc_queue.html

Du kan bruke fast størrelse, og du vil ha blokkert forbruker hvis ikke data er tilgjengelige osv. Uten å implementere det selv.

Kommentarer

  • Jeg gjorde legg merke til dette, men maskinen min (ikke i nettverk) så ut til å mangle dette. Når det er sagt, tror jeg at pop og push fungerer det samme, ikke-blokkerende returnerende bool, uansett om det lykkes eller ikke.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *