一种多线程基于计数无锁实现(C#)(转载)
来源:互联网 发布:java设计模式实现 编辑:程序博客网 时间:2024/06/13 16:53
转自:http://blog.csdn.net/chzuping/article/details/10960061 chzuping的专栏
chzuping的专栏
本文介绍一种不加锁,不使用原子操作的多线程同步机制。先申明下,该方案为我在实际编程中创造出来的,事先我没有在其中地方看到关于该方案的介绍。
在多线程编程中,我们经常会遇到线程同步问题,这时候加锁就变得必不可少。但是锁的使用会或多或少带来某些性能上的下降。下面先介绍一个多线程编程中经常遇到的问题模型,然后实现一种无锁解决方案。
问题模型:
R:表示某种资源,线程A往R中存放资源,线程B从R中取出资源。
先看看常规解决方法:
线程A往R中存放资源
1.获取锁(此处可能睡眠)。
2.存入资源。
3.修改资源计数。
4.释放锁。
线程B从R中取出资源
1.获取锁(此处可能睡眠)。
2.取出资源。
3.修改资源计数。
4.释放锁。
下面针对该模型实现一种无锁的解决方案:
首先定义一个数组ARRAY存在资源,假设数组的长度为L,然后再定义两个变量READ和WRITE。READ表示读计数,WRITE表示写计数。
该方案的基本思想为:
1.存入资源增加WRITE。
2.读取资源增加READ。
3.WRITE和READ都只增不减。
4.判断ARRAY存在空余空间,WRITE - READ < L。
5.判断ARRAY为空,WRITE = READ 。
6.定位读位置READ%L,定位写位置WRITE%L。
实际操作流程为:
初始化READ和WRITE为0。
线程A往R中存放一个资源
1.判断数组中的资源未满。
2.存放资源到ARRAY[WRITE%L]
3.增加WRITE。
线程B往R中读取一个资源
1.判断数组中的资源不为空。
2.存放资源到ARRAY[READ%L]
3.增加READ。
可能大家已经看出,上面的实现存在一个严重的问题,就是越界的问题,下面讨论解决方案:
1.越界后WRITE - READ需要保证正确。
大家知道无符号数有一个特性,
0x00000000-0xffffffff = 1;
0x00000000-0xfffffffe = 2;
只要把READ和WRITE定义成无符号数,就能保证WRITE - READ在越界后保证正确性。
2.WRITE%L 和 READ%L在越界后的正确性,我们需要保证以下等式成立:
0xffffffff%L = L -1
为了保证以上等式成立,可以将L设成2的n次方,对应32位整数,n的取值范围为0~31. 由于限定L为2的n次方,WRITE%L 和 READ%L可以写成WRITE&(L-1) 和 READ%L&(L-1).讨论:
该无锁实现对多线程编程常用的模型提出一种无锁实现,但在使用中还需注意一下几点:
1.为防止程序从高速缓存中取值,必须将变量READ和WRITE定义成volatile类型。
2.该方案要求缓冲区的长度为2的n次方,取值可以为1,2,4,8,16,32,64……,大部分时候可以满足应用上的需求。
3.该方案目前只适用于基于数组的缓冲区结构。
4.该方案目前只适一个读者,一个写者的情形,如果存在多个读者,多个写者,需要分别对读者和写者进行加锁,但是使用该方案还是可以减少锁的力度。
下面贴出参考测试代码:
- #include "stdafx.h"
- #include <windows.h>
- class ZwAsynCount
- {
- public:
- ZwAsynCount(unsigned uSize) //uSize必须为2的n次方
- {
- m_uReadCount = 0;
- m_uWriteCount = 0;
- m_uSize = uSize;
- }
- int Write() //返回元素位置 -1表示读失败
- {
- int nRet = -1;
- if (m_uWriteCount - m_uReadCount < m_uSize)
- {
- nRet = m_uWriteCount&(m_uSize-1);
- }
- return nRet;
- }
- void AddWrite(int nCount = 1)
- {
- m_uWriteCount += nCount;
- }
- int Read() //返回元素位置 -1表示写失败
- {
- int nRet = -1;
- if (m_uWriteCount - m_uReadCount > 0)
- {
- nRet = m_uReadCount&(m_uSize-1);
- }
- return nRet;
- }
- void AddRead(int nCount = 1)
- {
- m_uReadCount+= nCount;
- }
- private:
- unsigned m_uSize;
- volatile unsigned m_uReadCount;
- volatile unsigned m_uWriteCount;
- };
- class ZwTestShareBuffer
- {
- public:
- ZwTestShareBuffer():m_asynCount(128)
- {
- }
- BOOL Read()
- {
- BOOL bRet = FALSE;
- int nPos = m_asynCount.Read();
- if (nPos >= 0)
- {
- printf("read: %d\n",m_data[nPos]);
- bRet = TRUE;
- m_asynCount.AddRead();
- }
- return bRet;
- }
- BOOL Write(int nData)
- {
- BOOL bRet = FALSE;
- int nPos = m_asynCount.Write();
- if (nPos >= 0)
- {
- m_data[nPos] = nData;
- bRet = TRUE;
- m_asynCount.AddWrite();
- }
- return bRet;
- }
- private:
- ZwAsynCount m_asynCount;
- int m_data[128];
- };
- ZwTestShareBuffer TestAsynShareBuffer;
- DWORD WINAPI WriteProc(LPVOID lpParam)
- {
- int nData = 0;
- while(TRUE)
- {
- if (!TestAsynShareBuffer.Write(nData))
- {
- Sleep(1);
- }
- else
- {
- nData++;
- }
- }
- return 0;
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- ::CreateThread(NULL,0,WriteProc,NULL,0,NULL);
- while(TRUE)
- {
- if (!TestAsynShareBuffer.Read())
- {
- Sleep(1);
- }
- }
- return 0;
- }
0 0
- 一种多线程基于计数无锁实现(C#)(转载)
- 一种多线程基于计数无锁实现
- 一种基于CAS的无锁并发HashTable设计及C代码实现
- 智能型指针另一种实现(基于计数)
- 一种基于引用计数机制的智能指针实现
- 一种基于引用计数机制的智能指针实现
- 一种基于引用计数的智能指针的实现
- 计数排序算法实现(C版)
- 计数排序算法(C语言实现)
- 算法导论计数排序实现(C++)
- 高效C++无锁队列实现(转载)
- 高效C++无锁队列实现(转载)
- 一种基于Qt的可伸缩的全异步C/S架构服务器实现(五) 单层无中心集群
- 一种基于Qt的可伸缩的全异步C/S架构服务器实现(五) 单层无中心集群
- 引用计数的一种实现
- ASP.Net(C#)中基于ScriptManager-UpdatePanel的无刷新上传(用户控件)的实现
- 一种简单无锁队列的实现
- 一种基于Qt的可伸缩的全异步C/S架构服务器实现(四)数据库的多线程操作
- swift学习记录(枚举)
- Java对Oracle中Clob类型数据的读取和写入
- 进击的java程序员:分享的开端
- Yocto i.MX6 (TQIMX6) (02) : USB Wifi (TP-Link WN821N等设备)AR9170的Linux内核支持与固件使用
- ubuntu服务器硬件配置
- 一种多线程基于计数无锁实现(C#)(转载)
- sqlplus 命令行格式(set,col等)
- YunOS曙光初现----看好阿里云OS----阿冬专栏!!
- ubuntu 查看清理内核
- hdu--2138
- 转帖:网站服务架构
- android 在不同设备上使图片不失真
- ListActivity的使用方法
- 斐波那契数--递归和非递归实现