C++ 无锁队列 ABA <1>

实验环境: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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值