多线程编程5种方法实现线程同步.docx
- 文档编号:10958508
- 上传时间:2023-02-24
- 格式:DOCX
- 页数:13
- 大小:143.58KB
多线程编程5种方法实现线程同步.docx
《多线程编程5种方法实现线程同步.docx》由会员分享,可在线阅读,更多相关《多线程编程5种方法实现线程同步.docx(13页珍藏版)》请在冰豆网上搜索。
多线程编程5种方法实现线程同步
多线程编程--5种方法实现线程同步
1:
用Interlocked系列函数实现线程同步;
2:
用CRITICAL_SECTION及其系列函数实现线程同步;
3:
用RTL_SRWLOCK及其系列函数实现线程同步;
4:
用事件内核对象实现线程同步;
5:
用信号量内核对象实现线程同步;
1:
用Interlocked系列函数实现线程同步实例如下:
//旋转锁
#include
usingnamespacestd;
#include
#include
constintthreadNum=10;
HANDLEhThread[threadNum];
volatileunsignedintISOK=0;
unsignedint_stdcallInterlocked(PVOIDthreadId)
{
while(InterlockedExchange(&ISOK,1)==1);
cout<<"线程:
"<<*(int*)threadId<<"开始"< Sleep(100); cout<<"线程: "<<*(int*)threadId<<"结束"< InterlockedExchange(&ISOK,0); return0; } voidInterlockedTest() { intthreadId[threadNum]; for(inti=0;i { threadId[i]=i+1; } cout<<"1: 用Interlocked系列函数实现线程同步"< for(inti=0;i<10;i++){ hThread[i]=(HANDLE)_beginthreadex(NULL,0,Interlocked,threadId+i,0,NULL); } WaitForMultipleObjects(threadNum,hThread,TRUE,INFINITE); for(inti=0;i { CloseHandle(hThread[i]); } } InterlockedExchange确保以原子的方式操作数据。 执行速度非常快,缺点是如果要同步的部分执行的时间比较长的话,while循环会一直轮询操作,浪费CPU的时间,在单核CPU的系统中,可能会出现while一直暂用CPU导致其他线程不能修改ISOK的值,导致不能跳出while循环,出现死循环。 还有就是线程的优先级问题也能导致问题。 2: 用CRITICAL_SECTION及其系列函数实现线程同步实例如下: //关键段 #include usingnamespacestd; #include #include constintthreadNum=10; HANDLEhThread[threadNum]; CRITICAL_SECTIONg_cs;//构造一个CRITICAL_SECTION实例 unsignedint_stdcallCriticalSection(PVOIDthreadId) { EnterCriticalSection(&g_cs);//进入关键段 cout<<"线程: "<<*(int*)threadId<<"开始"< Sleep(100); cout<<"线程: "<<*(int*)threadId<<"结束"< LeaveCriticalSection(&g_cs);//进入关键段 return0; } voidCriticalSectionTest() { intthreadId[threadNum]; for(inti=0;i { threadId[i]=i+1; } InitializeCriticalSection(&g_cs);//初始化g_cs的成员 cout<<"2: 用CRITICAL_SECTION及其系列函数实现线程同步"< for(inti=0;i<10;i++){ hThread[i]=(HANDLE)_beginthreadex(NULL,0,CriticalSection,threadId+i,0,NULL); } WaitForMultipleObjects(threadNum,hThread,TRUE,INFINITE); for(inti=0;i { CloseHandle(hThread[i]); } DeleteCriticalSection(&g_cs);//删除关键段 } CRITICAL_SECTION同样是以原子的方式操作数据,也只有以原子的方式操作数据才能实现线程的同步,所有实现线程同步的方法,最核心的部分就是以原子的方式操作数据,CRITICAL_SECTION执行的速度非常快,其内部有一个事件内核对象,当出现资源争夺的时候,才会出现初始化这个事件内核对象,由于CRITICAL_SECTION执行非常快可能不会出现资源争夺,也就没有必要创建这个事件内核对象,这个事件内核对象创建后,会将当前线程之外的线程挂起,并记录这些线程需要这个资源,其他线程就不会浪费CPU的时间,而这些被挂起的线程将由用户模式变成内核模式,当这些线程需要的资源可用时,系统会将其中一个线程唤醒。 还有一点值得注意: 如果要同步的代码执行得很快,在出现争夺资源的时候,系统把其他线程挂起,而当前线程又马上执行完成了,系统又将挂起的线程唤醒,这个过程是非常浪费CPU的,也影响程序的性能,为了避免这种情况,可以结合旋转锁和CRITICAL_SECTION,先用旋转锁轮询一定次数,还不能获得资源,再将线程挂起,等待资源被释放,系统再将线程唤醒,实现这一功能的就是方法 InitializeCriticalSectionAndSpinCount( LPCRITICAL_SECTIONlpCriticalSection, DWORDdwSpinCount//旋转锁轮询的次数 ); 除了初始化CRITICAL_SECTION用的是方法InitializeCriticalSectionAndSpinCount,而不是方法InitializeCriticalSection,其他的都是一样的。 3: 用RTL_SRWLOCK及其系列函数实现线程同步实例如下: //读写锁 #include usingnamespacestd; #include #include constintthreadNum=10; HANDLEhThread[threadNum]; RTL_SRWLOCKlock;//构造一个CRITICAL_SECTION实例 unsignedint_stdcallSrwLock(PVOIDthreadId) { AcquireSRWLockExclusive(&lock);//进入读写锁 cout<<"线程: "<<*(int*)threadId<<"开始"< Sleep(100); cout<<"线程: "<<*(int*)threadId<<"结束"< ReleaseSRWLockExclusive(&lock);//进入读写锁 return0; } voidSrwLockTest() { intthreadId[threadNum]; for(inti=0;i { threadId[i]=i+1; } InitializeSRWLock(&lock);//初始化lock的成员 cout<<"3: 用RTL_SRWLOCK及其系列函数实现线程同步"< for(inti=0;i<10;i++){ hThread[i]=(HANDLE)_beginthreadex(NULL,0,SrwLock,threadId+i,0,NULL); } WaitForMultipleObjects(threadNum,hThread,TRUE,INFINITE); for(inti=0;i { CloseHandle(hThread[i]); } } SRWLock的目的和关键段是一样的,就是对资源的保护,不让其他线程访问。 不同的是,它区分线程是读线程还是写线程。 我们都是知道,一个资源可以同时被多个线程同时读,就是不能同时读,或是读写。 也是是说写必须是独占的方式,而读可以以共享的方式访问,如果以共享的方式访问肯定就比CRITICAL_SECTION性能好。 4: 用事件内核对象实现线程同步实例如下: //事件 #include usingnamespacestd; #include #include constintthreadNum=10; HANDLEhThread[threadNum]; HANDLEevent1; unsignedint_stdcallEvent(PVOIDthreadId) { WaitForSingleObject(event1,INFINITE); int*p=(int*)threadId; cout<<"线程: "<<*p<<"开始"< Sleep(100); cout<<"线程: "<<*p<<"结束"< SetEvent(event1); return1; } voidEventTest() { intthreadId[threadNum]; for(inti=0;i { threadId[i]=i+1; } event1=CreateEvent(NULL,false,true,NULL); cout<<"4: 用事件内核对象实现线程同步"< for(inti=0;i { hThread[i]=(HANDLE)_beginthreadex(NULL,0,Event,threadId+i,0,NULL); } WaitForMultipleObjects(threadNum,hThread,TRUE,INFINITE); for(inti=0;i { CloseHandle(hThread[i]); } CloseHandle(event1); } 用内核对象实现线程同步,一个函数是必须知道的,它就是WaitForSingleObject。 DWORDWaitForSingleObject( HANDLEhHandle,//内核对象的句柄 DWORDdwMilliseconds//等待时间 ); 该函数会一直等待,直到被指定的内核对象被触发为止,或是等待的时间结束返回。 CreateEvent( LPSECURITY_ATTRIBUTESlpEventAttributes,//安全控制 BOOLbManualReset,//true: 手动重置事件,false: 自动重置事件 BOOLbInitialState,//true: 有信号,false: 无信号 LPCWSTRlpName//事件名称 ); bManualReset为true表示事件触发了并一直处于触发状态,就像打开的门,打开之后就是一直开着,没有自动关上;false: 一打开放一个进去进关了,需要用SetEvent再次触发事件。 5: 用信号量内核对象实现线程同步实例如下: //信号量 #include usingnamespacestd; #include #include constintthreadNum=10; HANDLEhThread[threadNum]; HANDLEsemaphore; unsignedint_stdcallSemaphore(PVOIDthreadId) { WaitForSingleObject(semaphore,INFINITE); cout<<"线程: "<<*(int*)threadId<<"开始"< Sleep(100); cout<<"线程: "<<*(int*)threadId<<"结束"< ReleaseSemaphore(semaphore,1,NULL); return0; } voidSemaphoreTest() { intthreadId[threadNum]; for(inti=0;i { threadId[i]=i+1; } semaphore=CreateSemaphore(NULL,1,1,NULL); cout<<"5: 用信号量内核对象实现线程同步"< for(inti=0;i<10;i++){ hThread[i]=(HANDLE)_beginthreadex(NULL,0,Semaphore,threadId+i,0,NULL); } WaitForMultipleObjects(threadNum,hThread,TRUE,INFINITE); for(inti=0;i { CloseHandle(hThread[i]); } CloseHandle(semaphore); } 信号量内核对象用来对资源进行计数。 创建信号量内核对象的方法如下: CreateSemaphore( LPSECURITY_ATTRIBUTESlpSemaphoreAttributes,//安全控制 LONGlInitialCount,//初始资源数量 LONGlMaximumCount,//最大并发数量 LPCWSTRlpName//号量的名称 ); lMaximumCount表示最大并发数量,可以用来设置系统的最大并发数量,如果我们把他的值设为1,lInitialCount也设为1,就是只有一个资源,且每次只能一个线程访问,这样就可以实现线程同步。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 多线程 编程 方法 实现 线程 同步