• C++ 无锁队列实现


    上源码

      1 #ifndef __GLOBAL_LOCK_FREE_QUEUE_H__
      2 #define __GLOBAL_LOCK_FREE_QUEUE_H__
      3 
      4 #include <atomic>
      5 #include <list>
      6 
      7 #ifdef _WINDOWS
      8 #include <windows.h>
      9 //PVOID __cdecl InterlockedCompareExchangePointer(
     10 //    _Inout_ PVOID volatile *Destination,
     11 //    _In_    PVOID          Exchange,
     12 //    _In_    PVOID          Comparand
     13 //    );
     14 //
     15 //Parameters
     16 //    Destination [in, out]
     17 //A pointer to a pointer to the destination value.
     18 //    Exchange [in]
     19 //The exchange value.
     20 //    Comparand [in]
     21 //The value to compare to Destination.
     22 //    Return value
     23 //    The function returns the initial value of the Destination parameter.
     24 //    Remarks
     25 //    The function compares the Destination value with the Comparand value. If the Destination value is equal to the Comparand value, the Exchange value is stored in the address specified by Destination. Otherwise, no operation is performed.
     26 //    On a 64-bit system, the parameters are 64 bits and must be aligned on 64-bit boundaries; otherwise, the function will behave unpredictably. On a 32-bit system, the parameters are 32 bits and must be aligned on 32-bit boundaries.
     27 //    The interlocked functions provide a simple mechanism for synchronizing access to a variable that is shared by multiple threads. This function is atomic with respect to calls to other interlocked functions.
     28 #define __sync_bool_compare_and_swap(a,b,c) (InterlockedCompareExchangePointer((void*volatile*)a,c,b), (*a)==(c))
     29 #endif
     30 
     31 namespace DataCache
     32 {
     33 
     34     template <typename T>
     35     class LinkList
     36     {
     37     public:
     38         T data;
     39         LinkList<T> *next;
     40     };// class LinkeList<T>
     41 
     42     template <typename T>
     43     class LockFreeQueue
     44     {
     45     public:
     46         LockFreeQueue();
     47 
     48         void push_back(T t);
     49 
     50         T pop_front(void);
     51 
     52         bool isEmpty(void);
     53 
     54         int GetLength();
     55 
     56     private:
     57         LinkList<T> *head_;
     58         LinkList<T> *tail_;
     59         std::_Atomic_integral_t elementNumbers_;
     60     }; // class LockFreeQueue
     61 
     62     template <typename T>
     63     LockFreeQueue<T>::LockFreeQueue()
     64         :head_(NULL),
     65         tail_(new LinkList<T>),
     66         elementNumbers_(0)
     67     {
     68         head_ = tail_;
     69         tail_->next = NULL;
     70     }
     71 
     72     template <typename T>
     73     void LockFreeQueue<T>::push_back(T t)
     74     {
     75         auto newVal = new LinkList<T>;
     76         newVal->data = t;
     77         newVal->next = NULL;
     78 
     79         LinkList<T> *p;
     80         do
     81         {
     82             p = tail_;
     83         } while (!__sync_bool_compare_and_swap(&tail_->next, NULL, newVal));
     84 
     85         //move tail_
     86         __sync_bool_compare_and_swap(&tail_, tail_, newVal);
     87         elementNumbers_++;
     88     }
     89 
     90     template <typename T>
     91     T LockFreeQueue<T>::pop_front()
     92     {
     93         LinkList<T> *p;
     94 
     95         do
     96         {
     97             //record the first node.
     98             p = head_->next;
     99             if (!p)
    100             {
    101                 return 0;
    102             }
    103         } while (!__sync_bool_compare_and_swap(&head_->next, p, p->next));
    104 
    105         if (elementNumbers_ > 0) elementNumbers_--;
    106         if (elementNumbers_ == 0)
    107         {
    108             // if the queue is empty then the tail to header.
    109             do
    110             {
    111 
    112             } while (!__sync_bool_compare_and_swap(&tail_, p, head_));
    113         }
    114 
    115         return p->data;
    116     }
    117 
    118     template <typename T>
    119     bool LockFreeQueue<T>::isEmpty()
    120     {
    121         if (elementNumbers_ == 0)
    122         {
    123             return true;
    124         }
    125         else
    126         {
    127             return false;
    128         }
    129     }
    130 
    131     template <typename T>
    132     int LockFreeQueue<T>::GetLength()
    133     {
    134         return elementNumbers_;
    135     }
    136 
    137 }// namespace DataCache
    138 
    139 #endif
    View Code

    源码解析:

    重点在函数InterlockedCompareExchangePointer(a,c,b),其作用为如果a==b,则修改a的值为c,这是微软提供的一个原子操作的API,这里面通过定义这个宏,来进行queue入队列和出队列时的指针修改,达到无锁操作的目的,可以大幅提高队列的操作性能,避免过程中进行加锁操作。在GCC中已经原生支持了__sync_bool_compare_and_swap,所以这个宏的作用是针对MSVC版本提供的类似函数。

    测试代码:

     1 #include"lockFreeQueue.h"
     2 
     3 DataCache::LockFreeQueue<int> queue;
     4 
     5 void func1(void)
     6 {
     7     for(int i = 0; i <100000 ; i++)
     8     {
     9         queue.push_back(i);
    10     }
    11 }
    12 
    13 void func2(void)
    14 {
    15     for(int i = 100000; i < 200000; i++)
    16     {
    17         queue.push_back(i);
    18     }
    19 }
    20 
    21 void func5(void)
    22 {
    23     for(int i = 200000; i < 300000; i++)
    24     {
    25         queue.push_back(i);
    26     }
    27 }
    28 
    29 void func4(void)
    30 {
    31     for(int i = 400000; i < 500000; i++)
    32     {
    33         queue.push_back(i);
    34     }
    35 }
    36 
    37 void func3(void)
    38 {
    39     while (!queue.isEmpty())
    40     {
    41         std::cout<<queue.pop_front()<<" ";
    42     }
    43 
    44     std::cout<<std::endl;
    45 }
    46 
    47 int main(int argc,char **argv)
    48 {
    49     std::thread t1(func1);
    50     std::thread t2(func2);
    51     std::thread t5(func5);
    52     std::thread t6(func4);
    53 
    54     t1.join();
    55     t2.join();
    56     t5.join();
    57     t6.join();
    58 
    59     int length=queue.GetLength();
    60     assert(length==500000);
    61     return 0;
    62 }

     

  • 相关阅读:
    vue 解析二维码
    自定义组件双向数据绑定,父v-model,子value用.$emit('input', newVal)
    懒加载组件
    float双飞布局
    [转]MySQL 8.0 Public Key Retrieval is not allowed 错误的解决方法
    【转】nginx产生【413 request entity too large】错误的原因与解决方法
    [其它]三维立体图简单入门含样例
    [其它] 美图看看 黑色皮肤下载不了
    vue element 表格内容文字太长加提示
    gitee webide怎么暂存文件(吐槽,gitee的产品真是吃屎的)
  • 原文地址:https://www.cnblogs.com/lenmom/p/7857498.html
Copyright © 2020-2023  润新知