多线程编程5种方法实现线程同步.docx

上传人:b****5 文档编号:8148446 上传时间:2023-01-29 格式:DOCX 页数:12 大小:143.62KB
下载 相关 举报
多线程编程5种方法实现线程同步.docx_第1页
第1页 / 共12页
多线程编程5种方法实现线程同步.docx_第2页
第2页 / 共12页
多线程编程5种方法实现线程同步.docx_第3页
第3页 / 共12页
多线程编程5种方法实现线程同步.docx_第4页
第4页 / 共12页
多线程编程5种方法实现线程同步.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

多线程编程5种方法实现线程同步.docx

《多线程编程5种方法实现线程同步.docx》由会员分享,可在线阅读,更多相关《多线程编程5种方法实现线程同步.docx(12页珍藏版)》请在冰豆网上搜索。

多线程编程5种方法实现线程同步.docx

多线程编程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,就是只有一个资源,且每次只能一个线程访问,这样就可以实现线程同步。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 外语学习 > 韩语学习

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1