Pages - Menu

標籤

AWS (1) bash (1) Boost (2) C (2) CMake (2) Concurrency_Programming (3) CPP (37) Database (2) DNS (1) Docker (4) Docker-Compose (1) ELK (1) emacs (4) gcp (1) gdrive (1) git (1) gitbash (2) gitlab (1) kvm (4) Linux (5) MT4 (4) MT5 (4) Multicast (2) MySQL (2) Nijatrader8 (1) OpenCV (1) Python (4) QT5 (1) R (1) rdp (3) screenshot (1) ssh (3) Tabnine (1) TCP (1) TensorFlow (1) Tools (12) Ubuntu_1904 (11) Ubuntu_20_04 (5) UDP (1) VS2010 (1) VS2015 (1) VS2019 (1) WebServer (1) Win10 (1) winmerge (1) WSL (1) xrdp (1)

搜尋此網誌

2020年5月7日星期四

Concurrency message queue in C++

Aim

In this post, I would like to see how to build a concurrency message queue in C++ that is fast. The fastest message queue I can make at this moment is the Lock Free Ring Buffer message queue. There is more details in the result part.

Source

Testing method

There is a speed test framework implemented in SpeedTest class. No matter what type of message queue we are using, a number of message will be pushed into the MsgQ by multiple number of threads at the same time there are the same number of threads reading message from that MsgQ.

We then have a timer to count the total time that is needed to process all the messages.

We have different type of message queue:

Lock Free MsgQ

  1. MsgQLockFree with Ring Buffer

Using Linux Concurrency library

  1. MsgQOneLock with Ring Buffer
  2. MsgQTwoLock with Ring Buffer
  3. MsgQOneLock with LinkList 
  4. MsgQTwoLock with LinkList

Using C++ standard library

  1. MsgQOneLock with Ring Buffer
  2. MsgQTwoLock with Ring Buffer
  3. MsgQOneLock with LinkList 
  4. MsgQTwoLock with LinkList
As one can see that there are currently 3 types of message queue:
  1. Lock free
  2. One lock
  3. Two lock
We would like to see their difference in speed.

More on Queue

Lock Free

I learn this from here. I made a simplified version. This is a concurrency message queue but only support 2 threads. 1 thread is pushing message and 1 thread is getting message.
In this message queue we have no mutex lock. There are 2 pointers, one is pointing to the next empty slot(Tail) and the other is pointing to the next ready message slot(Head). The length of the message queue is a power of 2. Since there is no mutex lock, __sync_val_compare_and_swap() is used.

One Lock

The other type of message queue is a queue that is using one lock.
There is one mutex protecting the Head and Tail pointers. More than 2 threads can be supported.

Two Lock

There are two mutex protecting the Head and Tail pointers. More than 2 threads can be supported.

The Test

Hardware

  • Intel(R) Core(TM) i5-6500 CPU @ 3.20GHz
  • 4 core
  • 4 threads
  • Ubuntu 20.04 LTS

Test Info

  • 300000 messages
  • Threads
    • 1 in, 1 out
    • 2 in , 2 out
    • 4 in, 4 out
    • 10 in, 10 out
  • 5 total tests and get the average time spend

Result

MsgQ TypeThread INThread OUTTotal MessageTotal testTime spend Msec
Lock Free11300000546
One Lock113000005115
Two Lock113000005102.5

The above grape comparing 1 thread in and 1 thread out case. The lock free message queue is the fastest one. This is expected.


Thread IOTotal MessageTotal testMsec One LockMsec Two Lock
Two3000005122135.5
Four3000005133.5119
Ten3000005150.5124
The above graph shows that the speed of MsgQ with 2 locks is better. We have 2 threads IN and OUT, 4 threads and 10 threads in these tests.

Raw Result

MsgQLockFree_Linux11300000546
MsgQLockFree_LinkList_Std113000005100
MsgStackLockFree_LinkList_Std113000005296
MsgStackLockFree_LinkList_Std223000005406
MsgStackLockFree_LinkList_Std443000005806
MsgStackLockFree_LinkList_Std10103000005568
MsgQOneLock_RingBuf_Linux113000005111
MsgQOneLock_RingBuf_Linux223000005109
MsgQOneLock_RingBuf_Linux443000005135
MsgQOneLock_RingBuf_Linux10103000005186
MsgQTwoLock_RingBuf_Linux11300000586
MsgQTwoLock_RingBuf_Linux223000005135
MsgQTwoLock_RingBuf_Linux443000005132
MsgQTwoLock_RingBuf_Linux10103000005128
MsgQOneLock_RingBuf_Std113000005119
MsgQOneLock_RingBuf_Std223000005137
MsgQOneLock_RingBuf_Std443000005106
MsgQOneLock_RingBuf_Std10103000005115
MsgQTwoLock_RingBuf_Std113000005100
MsgQTwoLock_RingBuf_Std223000005136
MsgQTwoLock_RingBuf_Std443000005106
MsgQTwoLock_RingBuf_Std10103000005120
MsgQOneLock_LinkList_Linux113000005229
MsgQOneLock_LinkList_Linux223000005201
MsgQOneLock_LinkList_Linux443000005195
MsgQOneLock_LinkList_Linux10103000005197
MsgQTwoLock_LinkList_Linux113000005179
MsgQTwoLock_LinkList_Linux223000005268
MsgQTwoLock_LinkList_Linux443000005225
MsgQTwoLock_LinkList_Linux10103000005213
MsgQOneLock_LinkList_Std113000005250
MsgQOneLock_LinkList_Std223000005189
MsgQOneLock_LinkList_Std443000005209
MsgQOneLock_LinkList_Std10103000005223
MsgQTwoLock_LinkList_Std113000005166
MsgQTwoLock_LinkList_Std223000005267
MsgQTwoLock_LinkList_Std443000005212
MsgQTwoLock_LinkList_Std10103000005219
MsgQOneLock_Queue_Linux113000005203
MsgQOneLock_Queue_Linux223000005158
MsgQOneLock_Queue_Linux443000005152
MsgQOneLock_Queue_Linux10103000005172
MsgQOneLock_Queue_Std113000005178
MsgQOneLock_Queue_Std223000005151
MsgQOneLock_Queue_Std443000005150
MsgQOneLock_Queue_Std10103000005154

沒有留言:

發佈留言