多线程编程--5种方法实现线程同步
来源:互联网 发布:垃圾对人类的危害数据 编辑:程序博客网 时间:2024/05/17 04:14
多线程编程--5种方法实现线程同步 - 啊汉 - 博客园
http://www.cnblogs.com/hlxs/archive/2013/03/31/2991752.html
多线程编程--5种方法实现线程同步
1:用Interlocked系列函数实现线程同步;
2:用CRITICAL_SECTION及其系列函数实现线程同步;
3:用RTL_SRWLOCK及其系列函数实现线程同步;
4:用事件内核对象实现线程同步;
5:用信号量内核对象实现线程同步;
1:用Interlocked系列函数实现线程同步实例如下:
//旋转锁#include <iostream> using namespace std; #include <process.h>#include <windows.h> const int threadNum=10;HANDLE hThread[threadNum];volatile unsigned int ISOK=0;unsigned int _stdcall Interlocked(PVOID threadId){ while(InterlockedExchange(&ISOK,1)==1) ; cout<<"线程:"<<*(int*)threadId<<"开始"<<endl; Sleep(100); cout<<"线程:"<<*(int*)threadId<<"结束"<<endl; InterlockedExchange(&ISOK,0); return 0;} void InterlockedTest(){ int threadId[threadNum]; for(int i=0;i<threadNum;i++) { threadId[i]=i+1; } cout<<"1:用Interlocked系列函数实现线程同步"<<endl; for(int i=0;i<10;i++){ hThread[i]=(HANDLE)_beginthreadex(NULL, 0, Interlocked,threadId+i, 0, NULL); } WaitForMultipleObjects(threadNum, hThread, TRUE, INFINITE); for(int i=0;i<threadNum;i++) { CloseHandle(hThread[i]); } }
InterlockedExchange确保以原子的方式操作数据。执行速度非常快,缺点是如果要同步的部分执行的时间比较长的话,while循环会一直轮询操作,浪费CPU的时间,在单核CPU的系统中,可能会出现while一直暂用CPU导致其他线程不能修改ISOK的值,导致不能跳出while循环,出现死循环。还有就是线程的优先级问题也能导致问题。
2:用CRITICAL_SECTION及其系列函数实现线程同步实例如下:
//关键段 #include <iostream> using namespace std; #include <process.h>#include <windows.h> const int threadNum=10;HANDLE hThread[threadNum]; CRITICAL_SECTION g_cs;//构造一个CRITICAL_SECTION实例unsigned int _stdcall CriticalSection(PVOID threadId){ EnterCriticalSection(&g_cs);//进入关键段 cout<<"线程:"<<*(int*)threadId<<"开始"<<endl; Sleep(100); cout<<"线程:"<<*(int*)threadId<<"结束"<<endl; LeaveCriticalSection(&g_cs);//进入关键段 return 0;}void CriticalSectionTest(){ int threadId[threadNum]; for(int i=0;i<threadNum;i++) { threadId[i]=i+1; } InitializeCriticalSection(&g_cs);//初始化g_cs的成员 cout<<"2:用CRITICAL_SECTION及其系列函数实现线程同步"<<endl; for(int i=0;i<10;i++){ hThread[i]=(HANDLE)_beginthreadex(NULL, 0, CriticalSection,threadId+i, 0, NULL); } WaitForMultipleObjects(threadNum, hThread, TRUE, INFINITE); for(int i=0;i<threadNum;i++) { CloseHandle(hThread[i]); } DeleteCriticalSection(&g_cs);//删除关键段}
CRITICAL_SECTION同样是以原子的方式操作数据,也只有以原子的方式操作数据才能实现线程的同步,所有实现线程同步的方法,最核心的部分就是以原子的方式操作数据,CRITICAL_SECTION执行的速度非常快,其内部有一个事件内核对象,当出现资源争夺的时候,才会出现初始化这个事件内核对象,由于CRITICAL_SECTION执行非常快可能不会出现资源争夺,也就没有必要创建这个事件内核对象,这个事件内核对象创建后,会将当前线程之外的线程挂起,并记录这些线程需要这个资源,其他线程就不会浪费CPU的时间,而这些被挂起的线程将由用户模式变成内核模式,当这些线程需要的资源可用时,系统会将其中一个线程唤醒。
还有一点值得注意:如果要同步的代码执行得很快,在出现争夺资源的时候,系统把其他线程挂起,而当前线程又马上执行完成了,系统又将挂起的线程唤醒,这个过程是非常浪费CPU的,也影响程序的性能,为了避免这种情况,可以结合旋转锁和CRITICAL_SECTION,先用旋转锁轮询一定次数,还不能获得资源,再将线程挂起,等待资源被释放,系统再将线程唤醒,实现这一功能的就是方法
InitializeCriticalSectionAndSpinCount(
LPCRITICAL_SECTION lpCriticalSection,
DWORD dwSpinCount//旋转锁轮询的次数
);
除了初始化CRITICAL_SECTION用的是方法InitializeCriticalSectionAndSpinCount,而不是方法InitializeCriticalSection,其他的都是一样的。
3:用RTL_SRWLOCK及其系列函数实现线程同步实例如下:
//读写锁 #include <iostream> using namespace std; #include <process.h>#include <windows.h> const int threadNum=10;HANDLE hThread[threadNum]; RTL_SRWLOCK lock;//构造一个CRITICAL_SECTION实例unsigned int _stdcall SrwLock(PVOID threadId){ AcquireSRWLockExclusive(&lock);//进入读写锁 cout<<"线程:"<<*(int*)threadId<<"开始"<<endl; Sleep(100); cout<<"线程:"<<*(int*)threadId<<"结束"<<endl; ReleaseSRWLockExclusive(&lock);//进入读写锁 return 0;} void SrwLockTest(){ int threadId[threadNum]; for(int i=0;i<threadNum;i++) { threadId[i]=i+1; } InitializeSRWLock(&lock);//初始化lock的成员 cout<<"3:用RTL_SRWLOCK及其系列函数实现线程同步"<<endl; for(int i=0;i<10;i++){ hThread[i]=(HANDLE)_beginthreadex(NULL, 0, SrwLock,threadId+i, 0, NULL); } WaitForMultipleObjects(threadNum, hThread, TRUE, INFINITE); for(int i=0;i<threadNum;i++) { CloseHandle(hThread[i]); } }
SRWLock的目的和关键段是一样的,就是对资源的保护,不让其他线程访问。不同的是,它区分线程是读线程还是写线程。我们都是知道,一个资源可以同时被多个线程同时读,就是不能同时读,或是读写。也是是说写必须是独占的方式,而读可以以共享的方式访问,如果以共享的方式访问肯定就比CRITICAL_SECTION性能好。
4:用事件内核对象实现线程同步实例如下:
//事件#include <iostream> using namespace std; #include <process.h>#include <windows.h> const int threadNum=10;HANDLE hThread[threadNum];HANDLE event1; unsigned int _stdcall Event(PVOID threadId){ WaitForSingleObject(event1,INFINITE); int* p=(int*)threadId; cout<<"线程:"<<*p<<"开始"<<endl; Sleep(100); cout<<"线程:"<<*p<<"结束"<<endl; SetEvent(event1); return 1;}void EventTest(){ int threadId[threadNum]; for(int i=0;i<threadNum;i++) { threadId[i]=i+1; } event1=CreateEvent(NULL,false,true,NULL); cout<<"4:用事件内核对象实现线程同步"<<endl; for(int i=0;i<threadNum;i++) { hThread[i] =(HANDLE)_beginthreadex(NULL, 0, Event ,threadId+i, 0, NULL); } WaitForMultipleObjects(threadNum, hThread, TRUE, INFINITE); for(int i=0;i<threadNum;i++) { CloseHandle(hThread[i]); } CloseHandle(event1);}
用内核对象实现线程同步,一个函数是必须知道的,它就是WaitForSingleObject。
DWORD WaitForSingleObject(
HANDLE hHandle,//内核对象的句柄
DWORD dwMilliseconds//等待时间
);
该函数会一直等待,直到被指定的内核对象被触发为止,或是等待的时间结束返回。
CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,//安全控制
BOOL bManualReset,//true:手动重置事件,false:自动重置事件
BOOL bInitialState,//true:有信号,false:无信号
LPCWSTR lpName//事件名称
);
bManualReset为true表示事件触发了并一直处于触发状态,就像打开的门,打开之后就是一直开着,没有自动关上;false:一打开放一个进去进关了,需要用SetEvent再次触发事件。
5:用信号量内核对象实现线程同步实例如下:
//信号量#include <iostream> using namespace std; #include <process.h>#include <windows.h> const int threadNum=10;HANDLE hThread[threadNum];HANDLE semaphore; unsigned int _stdcall Semaphore(PVOID threadId){ WaitForSingleObject(semaphore, INFINITE); cout<<"线程:"<<*(int*)threadId<<"开始"<<endl; Sleep(100); cout<<"线程:"<<*(int*)threadId<<"结束"<<endl; ReleaseSemaphore(semaphore,1,NULL); return 0;} void SemaphoreTest(){ int threadId[threadNum]; for(int i=0;i<threadNum;i++) { threadId[i]=i+1; } semaphore=CreateSemaphore(NULL,1,1,NULL); cout<<"5:用信号量内核对象实现线程同步"<<endl; for(int i=0;i<10;i++){ hThread[i]=(HANDLE)_beginthreadex(NULL, 0, Semaphore,threadId+i, 0, NULL); } WaitForMultipleObjects(threadNum, hThread, TRUE, INFINITE); for(int i=0;i<threadNum;i++) { CloseHandle(hThread[i]); } CloseHandle(semaphore);}
信号量内核对象用来对资源进行计数。创建信号量内核对象的方法如下:
CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,//安全控制
LONG lInitialCount,//初始资源数量
LONG lMaximumCount,//最大并发数量
LPCWSTR lpName//号量的名称
);
lMaximumCount表示最大并发数量,可以用来设置系统的最大并发数量,如果我们把他的值设为1,lInitialCount也设为1,就是只有一个资源,且每次只能一个线程访问,这样就可以实现线程同步。
在实现线程同步时,建议用方法2和方法3,如不能解决你的需求,再用方法4,方法5,用内核对象实现的线程同步性能要差一些。
多线程编程5中实现线程同步的方法介绍差多就到此了,大家可能还有一些疑问,可以看看我之前关于多线程基础知识的一些介绍:
Windows线程基础
Windows内核对象简介
Windows几种线程同步方法介绍
我的博客目录
- 多线程编程--5种方法实现线程同步
- 多线程编程--5种方法实现线程同步
- 多线程编程--5种方法实现线程同步
- 多线程编程--5种方法实现线程同步
- 多线程编程--5种方法实现线程同步
- 多线程编程--5种方法实现线程同步
- 多线程编程5 线程同步
- 多线程编程——线程同步方法
- 多线程编程:线程同步
- 【多线程】多线程编程:线程同步
- 多线程的两种实现方法?实现线程同步的方法?
- Linux多线程编程及线程同步方法总结
- 多线程编程Demo[利用事件对象实现线程同步]
- windows C++多线程编程高级篇 实现线程同步
- 多线程编程入门(1):线程的实现,停止,同步,通信
- Linux多线程编程之线程结合互斥锁实现同步
- 多线程编程与线程同步
- java多线程有几种实现方法?线程之间如何同步
- 宏定义的黑魔法 - 宏菜鸟起飞手册
- 日历记事本
- 操作系统习题
- 大陆怎么登陆谷歌和Gmail邮箱?【外游VPN登陆注册谷歌】
- Android 用户界面编程技巧
- 多线程编程--5种方法实现线程同步
- 《C#程序设计》猜猜看小游戏制作
- socket nio 多线程接收客户端信息
- 用Lua编写iOS程序
- iOS开发之UITableView的滚动优化以及隐藏特性的使用
- 自动派生
- Navicat导出mysql的查询结果为Excel文档
- (转)informatica 面试题大全
- C语言之基本算法11—牛顿迭代法求平方根