Multithreaded message with messages in C ++

I have been instructed to modify the synchronous program C so that it can work in parallel. The goal is to make it as portable as possible, as it is an open source program that many people use. Because of this, I thought it was best to wrap the program at C ++ level so that I could use boost boost libraries. I have already done this and everything works as expected.

The problem I am facing is to decide which is the best approach for passing messages between threads. Fortunately, the architecture of the program is several manufacturers and one consumer. Even better, the message order is not important. I read that one-producer / one-consumer (SPSC) queues will benefit from this architecture. Anyone with multi-threaded programming have any tips? I am completely new to this. Any code examples using boost to implement SPSC will also be welcome.

+6
source share
3 answers

Below is the method that I used for my joint multitask / multithreaded library (MACE) http://bytemaster.github.com/mace/ . It has the advantage of locking, unless the queue is empty.

struct task { boost::function<void()> func; task* next; }; boost::mutex task_ready_mutex; boost::condition_variable task_ready; boost::atomic<task*> task_in_queue; // this can be called from any thread void thread::post_task( task* t ) { // atomically post the task to the queue. task* stale_head = task_in_queue.load(boost::memory_order_relaxed); do { t->next = stale_head; } while( !task_in_queue.compare_exchange_weak( stale_head, t, boost::memory_order_release ) ); // Because only one thread can post the 'first task', only that thread will attempt // to aquire the lock and therefore there should be no contention on this lock except // when *this thread is about to block on a wait condition. if( !stale_head ) { boost::unique_lock<boost::mutex> lock(task_ready_mutex); task_ready.notify_one(); } } // this is the consumer thread. void process_tasks() { while( !done ) { // this will atomically pop everything that has been posted so far. pending = task_in_queue.exchange(0,boost::memory_order_consume); // pending is a linked list in 'reverse post order', so process them // from tail to head if you want to maintain order. if( !pending ) { // lock scope boost::unique_lock<boost::mutex> lock(task_ready_mutex); // check one last time while holding the lock before blocking. if( !task_in_queue ) task_ready.wait( lock ); } } 
+7
source

If there is only one consumer, but several manufacturers, then I would use an array or some data-like data structure with access time O (1), where each slot in the array represents a queue of one producer-consumer. A big advantage for a single producer-producer queue is that you can make it unlockable without any explicit synchronization mechanisms, which makes it a very fast data structure in a multi-threaded environment. See my answer here for implementing the voice queue of a single consumer producer.

+1
source

There are many examples of producer-consumer queues on the network that are safe for multiple manufacturers / consumers. @bytemaster posted a post that uses a link inside each post to prevent queues from being stored in the queue class itself - this is a great approach, I use it myself in the built-in tasks.

If the queue class should contain storage, I usually start the N-sized pool queue loaded with instances of the N * message class at startup. Topics that need to be connected must push the message * out of the pool, download it and queue it up. When the message "ends up" eventually * returns to the pool. This limits the number of messages, and therefore, all queues should be only length N - no resizing, no new (), no deletion (), simple leak detection.

+1
source

Source: https://habr.com/ru/post/922098/


All Articles