实验环境:vs2013 新建一个无stdafx.h预编译头的控制台程序,然后复制以下代码
1、链表实现无锁队列
2、数组实现无锁队列
1、链表
注意: Enqueue函数中有使用new分配内存,本人在windows下使用VS2013编译,这里的new是线程安全的?并且如果换成LINUX或者其它系统的其它编译器,则可能由于new库不支持多线程而导致new不是线程安全的。因此,移植到其它系统时可以把在new前后加锁或者把new动作放在Enqueue函数外面,函数参数加一个参数即可!!
#include <stdio.h>
#include <process.h>
#include <windows.h>
#include <vector>
#include <iostream>
using namespace std;
#define CAS(a,b,c) (InterlockedCompareExchangePointer((PVOID*)a,(PVOID)c,(PVOID)b) == b)
struct Node
{
void *data;
Node *next;
};
struct Queue
{
Node *head;
Node *tail;
};
//初始化:最开始需要有一个空的节点
void InitQueue(Queue *&queue)
{
Node *node = new Node;
node->next = nullptr;
queue = new Queue;
queue->head = queue->tail = node;
}
void UnInitQueue(Queue *queue)
{
if(queue != nullptr)
{
Node* node = queue->head;
Node* next = nullptr;
while(node != nullptr)
{
next = node->next;
delete node;
node = next;
}
delete queue;
}
}
void Enqueue(Queue *queue,void *data)
{
Node *node, *tail, *next;
node = new Node;
node->data = data;
node->next = nullptr;
while (true)
{
tail = queue->tail;
next = tail->next;
if (queue->tail != tail)
continue;
if (next != nullptr)
{
CAS(&queue->tail, tail, next);
continue;
}
if (CAS(&tail->next, nullptr, node))
break;
}
CAS(&queue->tail, tail, node);
}
void* Dequeue(Queue *queue)
{
Node *head, *tail, *next;
void* data = nullptr;
while (true)
{
head = queue->head;
tail = queue->tail;
next = head->next;
if (queue->head != head)
continue;
if (next == nullptr)
return nullptr;
if (head == tail)
{
CAS(&queue->tail,tail,next);
continue;
}
//多消费者,next内存可能已经释放,next->data程序可能崩溃,单消费者,则不可能存在已经释放的情况
data = next->data;
//存在ABA问题
if (CAS(&queue->head, head, next))
break;
}
delete head;
return data;
}
/测试代码///
struct Test
{
int id; //线程索引
int num; //每个线程生产元素个数
Queue *queue;
HANDLE event;
int count;//每个消费者线程消费的个数
};
unsigned int __stdcall EnqueueThread(void *data)
{
Test *test = (Test*)data;
Queue *queue = test->queue;
int num = test->num;
int start = num * (test->id+1);
int end = start - num;
::SetEvent(test->event);
while (start > end)
{
int *a = new int;
*a = start;
Enqueue(queue, a);
start--;
}
return 0;
}
unsigned int __stdcall DequeueThread(void *data)
{
Test *test = (Test*)data;
Queue *queue = test->queue;
int id = test->id;
int &count = test->count;
::SetEvent(test->event);
int null_num = 0,num = 0;
while (true)
{
int * ptr = (int*)Dequeue(queue);
if (ptr == nullptr)
null_num++;
else
{
delete ptr;ptr = nullptr;
num++;
}
if (null_num == 5000000) break;
}
Sleep(100);
cout << "该消费者线程索引=" << id << ",退出时消费元素个数为 num=" << num << " null_num=" << null_num << endl;
count = num;
return 0;
}
void test()
{
Queue *queue = nullptr;
InitQueue(queue);
HANDLE hThrea