There is a single write thread, multiple read thread concurrency scenarios, such as the reading and updating of measurement data, consumers will be more, producers only one. Consider the example:
On the left is a classic solution that locks the entire data operation. For a write data thread, it is obviously a waste to lock all the read threads. A read-write lock (Reader/writer lock) is proposed, even if a read-write lock is used, the essence is the same, and under POSIX pthread its internal implementation is based on mutexes, so it is more expensive. If there is not a heavy read operation to counteract the overhead it introduces, it will cause a decrease in performance. There are several sets of test data to prove this. Myself I did the validation, get the data as follows (a single write thread, 20 read threads), using read-write locks instead of using a mutex is slower. For more information, refer to two links:
* Mutex or Reader Writer Lock
* Multi-threaded programming:efficiency of locking
This kind of problem, in the database domain has a kind of solution, is called Multiversion Concurrency Control, its purpose is to increase the data copy to ensure that the user can use every time the complete data, but not necessarily the newest data. To simplify a little bit, the idea is to create a copy of the data dedicated to writing. When the data is fully ready, switch it out for other threads to read. The original data is converted to the next write use. This is the way that is shown in the right side.
With this scheme, as long as the handling of the writing/reading lock on the can. The performance overhead of this test is because the lock processing time is very short, better than the general mutex and Reader/writer lock (the last algorithm):
The details are not unfolded. There are some more generic ways, called spin Buffer, that interest can be further studied.
The following source code is provided for reference:
#include <pthread.h>#include <iostream>#include <stdio.h>#include <unistd.h>#include <ctime>//#define USE_MUTEX//#define Use_rw_lock//X + Y = 0typedef struct_data{intXintY;} Data;namespace{Data globaldata[2] = {{1,-1}, {1,-1}};intWriteindex =0;intReadingindex =1;floatGlobalreadingtimecost =0.0f;#ifdef Use_mutexpthread_mutex_t mutex = Pthread_mutex_initializer;#endif#ifdef Use_rw_lockpthread_rwlock_t Rwlock;#endif Const intThread_number = -;}void* Write_thread (void* param) {clock_t begin_time =STD:: Clock (); for(intI=1; i<= +; i++) {globaldata[writeindex].x = i; GLOBALDATA[WRITEINDEX].Y =-1I Usleep1);#ifdef Use_mutexPthread_mutex_lock (&mutex);#endif#ifdef Use_rw_lockPthread_rwlock_rdlock (&rwlock);#endifReadingindex = Writeindex; Writeindex = (Writeindex +1) %2;#ifdef Use_mutexPthread_mutex_unlock (&mutex);#endif#ifdef Use_rw_lockPthread_rwlock_unlock (&rwlock);#endifUsleep -); }STD::cout<<"[Writing Thread]"<<float(STD:: Clock ()-begin_time)/clocks_per_sec * +<<STD:: Endl;returnNULL;}void* Read_thread (void* param) {clock_t begin_time =STD:: Clock (); for(intI=1; i<=20000; i++) {#ifdef Use_mutexPthread_mutex_lock (&mutex);#endif#ifdef Use_rw_lockPthread_rwlock_wrlock (&rwlock);#endif intindex = Readingindex;#ifdef Use_mutexPthread_mutex_unlock (&mutex);#endif#ifdef Use_rw_lockPthread_rwlock_unlock (&rwlock);#endif intx = globaldata[index].x;inty = globaldata[index].y;if(x + Y! =0) {STD::cout<<STD:: Endl <<"wrong data:"<< x <<","<< y <<STD:: Endl; } usleep (3); }STD::cout<<"[Reading Thread]"<<float(STD:: Clock ()-begin_time)/clocks_per_sec * +<<STD:: Endl;returnNULL;}intMainvoid) {intRET =0; pthread_t Id[thread_number];#ifdef Use_rw_lockPthread_rwlock_init (&rwlock, NULL);#endifclock_t Begin_time =STD:: Clock ();//One writing threadret = Pthread_create (&id[0], NULL, write_thread, NULL);if(ret) {STD::cout<<"Failed to launch writing thread."<<STD:: Endl;return-1; }//Four reading threads for(intI=1; i<thread_number; i++) {pthread_create (&id[i], NULL, read_thread, NULL); } for(intI=0; i<=thread_number; i++) {pthread_join (id[i], NULL); }STD::cout<<"Cost:"<<float(STD:: Clock ()-begin_time)/clocks_per_sec * +<<STD:: Endl;return 0;}
Compile the test using the following method:
g++-std=c++11-DUSE_MUTEXthread.-lpthread-othread
Write a document about multi-threading algorithm selection when you are free!
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
A read-write lock that is not real