Gyártói fogyasztó szálakkal és boost ring puffer használatával

Két szálam van, az egyik a gyártó, a másik pedig a fogyasztó. Fogyasztóm mindig késik (valamilyen költséges függvényhívás miatt, amelyet az alábbi kódban szimulálnak alvás közben), ezért gyűrűpuffert használtam, mivel megengedhettem magamnak egyes események elvesztését.

Arra vagyok kíváncsi, hogy a reteszelésem rendben van-e, és általános c ++ felülvizsgálati megjegyzések.

#include <iostream> #include <thread> #include <chrono> #include <vector> #include <atomic> #include <boost/circular_buffer.hpp> #include <condition_variable> #include <functional> std::atomic<bool> mRunning; std::mutex m_mutex; std::condition_variable m_condVar; class VecBuf { private: std::vector<int8_t> vec; public: VecBuf() = default; VecBuf(std::vector<int8_t> v) { vec = v; } }; std::vector<int8_t> data{ 10, 20, 30 }; class Detacher { public: template<typename Function, typename ... Args> void createTask(Function &&func, Args&& ... args) { m_threads.emplace_back(std::forward<Function>(func), std::forward<Args>(args)...); } Detacher() = default; Detacher(const Detacher&) = delete; Detacher & operator=(const Detacher&) = delete; Detacher(Detacher&&) = default; Detacher& operator=(Detacher&&) = default; ~Detacher() { for (auto& thread : m_threads) { thread.join(); } } private: std::vector<std::thread> m_threads; }; void foo_1(boost::circular_buffer<VecBuf> *cb) { while (mRunning) { std::unique_lock<std::mutex> mlock(m_mutex); m_condVar.wait(mlock, [=]() { return !cb->empty(); }); VecBuf local_data(cb->front()); cb->pop_front(); mlock.unlock(); if (!mRunning) { break; } //simulate time consuming function call and consume local_data here std::this_thread::sleep_for(std::chrono::milliseconds(16)); } while (cb->size()) { VecBuf local_data(cb->front()); cb->pop_front(); if (!mRunning) { break; } } } void foo_2(boost::circular_buffer<VecBuf> *cb) { while (mRunning) { std::unique_lock<std::mutex> mlock(m_mutex); while (cb->full()) { mlock.unlock(); /* can we do better than this? */ std::this_thread::sleep_for(std::chrono::milliseconds(100)); mlock.lock(); } cb->push_back(VecBuf(data)); m_condVar.notify_one(); } } int main() { mRunning = true; boost::circular_buffer<VecBuf> cb(100); Detacher thread_1; thread_1.createTask(foo_1, &cb); Detacher thread_2; thread_2.createTask(foo_2, &cb); std::this_thread::sleep_for(std::chrono::milliseconds(20000)); mRunning = false; } 

Válasz

 /* can we do better than this? */ 

Kör alakú pufferkörnyezetben az elfoglalt várakozás elkerülésének szokásos módja két szemafor. Először blokkolja a gyártót, ha a puffer megtelt, és a második, hogy blokkolja a fogyasztót, ha a puffer üres. Amint egy folyamat átengedi a szemaforját és elvégzi a feladatát, jeleznie kell a társát.


A kör alakú puffer akkor jó, ha a fogyasztó csak néha késik és nem lehet megengedheti magának az adatok elvesztését. Az Ön helyzetében ez rossz megoldásnak tűnik: a termelőt elfojtja a fogyasztás mértéke, és a fogyasztót bemutatják az elavult adatoknak.

Tipikus válasz az, hogy hagyja a termelőt teljes sebességgel működni. , és háromszoros puffer a termelés (legalább garantálja, hogy a fogyasztó megkapja a legutóbb előállított adatokat). Kérjük, bocsássa meg a szégyentelen önreklámot .

Hozzászólások

  • köszönöm az értékelést megjegyzés és a link. Az én esetemben azonban a fogyasztóm csak egy ideig blokkol. Azt hiszem, még mindig van értelme a jelenlegi megoldásom helyett szemaforokat használni a + változó feltétel használatával.
  • @nomanpouigt " egy ideig " egészen más, mint a " mindig későn ".
  • sajnálom, a gyűrűpufferre gondolok A méretet úgy választják meg, hogy képes legyen késleltetni. Kíváncsi a c ++ nyelven, hogy nincsenek szemaforok, és ezt mutexek és feltételváltozó segítségével valósítják meg, tehát ha van értelme szemaforokat használni.
  • Tudná részletezni a tripple puffer megoldását is, és hogyan lenne alkalmazható esetemben ? Nem ' ne zárja le a termelői oldalt, és hagyja futni, és a gyártó puffert tripla-pufferozni kell, hogy a fogyasztók friss adatokhoz jussanak túllépés esetén?

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük