多核程序设计课件5windows多线程编程.ppt

上传人:wj 文档编号:12991437 上传时间:2023-06-10 格式:PPT 页数:69 大小:387KB
下载 相关 举报
多核程序设计课件5windows多线程编程.ppt_第1页
第1页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第2页
第2页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第3页
第3页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第4页
第4页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第5页
第5页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第6页
第6页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第7页
第7页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第8页
第8页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第9页
第9页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第10页
第10页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第11页
第11页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第12页
第12页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第13页
第13页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第14页
第14页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第15页
第15页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第16页
第16页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第17页
第17页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第18页
第18页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第19页
第19页 / 共69页
多核程序设计课件5windows多线程编程.ppt_第20页
第20页 / 共69页
亲,该文档总共69页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

多核程序设计课件5windows多线程编程.ppt

《多核程序设计课件5windows多线程编程.ppt》由会员分享,可在线阅读,更多相关《多核程序设计课件5windows多线程编程.ppt(69页珍藏版)》请在冰点文库上搜索。

多核程序设计课件5windows多线程编程.ppt

第四章Windows多线程编程及调优,浙江大学计算机学院,Windows多线程API,在Windows平台下可以通过Windows的线程库来实现多线程编程提供的接口Win32API或MFC.NetFramework实现方式的多样化给Windows编程带来了很大的灵活性也使得多线程编程变得复杂,Windows线程库,Win32APIWindows操作系统为内核以及应用程序之间提供的接口将内核提供的功能进行函数封装应用程序通过调用相关的函数获得相应的系统功能。

MFC微软基础函数类库(MicrosoftFoundationClasses)用类库的方式将Win32API进行封装,以类的方式提供.NETFramework构成公共语言运行库(CommonLanguageRuntime,CLR)文件加载器、垃圾收集器、安全系统Framework类库(FrameworkClassLibrary,FCL).NET基础类库的System.Threading命名空间提供了大量的类和接口来支持多线程所有与多线程机制相关的类都存放在System.Threading命名空间中,使用win32线程API,Win32函数库中提供了操作多线程的函数,包括创建线程、管理线程、终止线程、线程同步等接口。

提供操作系统级别的创建线程的操作线程函数DWORDWINAPIThreadFunc(LPVOIDlpvThreadParm);线程创建HANDLECreateThread(LPSECURITY_ATTRIBUTESlpThreadAttributes,SIZE_TdwStackSize,LPTHREAD_START_ROUTINElpStartAddress,LPVOIDlpParameter,DWORDdwCreationFlags,LPDWORDlpThreadId);,第一个参数lpThreadAtt,是一个指向SECURITY-ATTRIBUTES结构的指针,该结构制定了线程的安全属性,缺省为NULL。

第二个参数dwStackSize,是栈的大小,一般设置为0。

第三个参数LPTHREAD_START_ROUTINE是新线程开始执行时,线程函数的入口地址。

它必须是将要被新线程执行的函数地址,不能为NULL。

lpStartAddress参数指定了线程函数的地址,新建线程将从此地址开始执行,直到return语句返回,线程运行结束,把控制权交给操作系统。

第四个参数lpParameter,是线程函数定义的参数。

可以通过这个参数传送值,包括指针或者NULL。

第五个参数dwCreationFlags,控制线程创建的附加标志,可以设置两种值。

0表示线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用;第六个参数lpThreadID,为指向32位变量的指针,该参数接受所创建线程的ID号。

如果创建成功则返回线程的句柄,否则返回NULL。

_beginthread,创建线程还可以用process.h头文件中声明的C执行时期链接库函数_beginthread。

在回调入口函数之前进行一些线程相关的CRT的初始化操作语法:

hThread=_beginthread(void(_cdecl*start_address)(void*),unsignedstack_size,void*arglist);线程函数的语法:

void_cdeclThreadProc(void*pParam);,使用_beginthread创建线程的例子,#includestdafx.h#include#include#include#includeusingnamespacestd;voidThreadFunc1(PVOIDparam)while

(1)Sleep(1000);coutThisisThreadFunc1endl;voidThreadFunc2(PVOIDparam)while

(1),Sleep(1000);coutThisisThreadFunc2endl;intmain()inti=0;_beginthread(ThreadFunc1,0,NULL);_beginthread(ThreadFunc2,0,NULL);Sleep(3000);coutendendl;return0;,线程管理,设置线程的优先级一个线程被创建时,它的优先级等于它所属进程的优先级SetThreadPriority函数设置线程的相对优先级BoolSetThreadPriority(HANDLEhPriority,intnPriority)线程与包含它的进程的优先级关系如下:

线程优先级=进程优先级+线程相对优先级,设置线程的优先级,参数hPriority是指向待设置的线程句柄进程的优先级包括:

实时:

REALTIME_PRIORITY_CLASS;高:

HIGH_PRIORITY_CLASS;高于正常:

ABOVE_NORMAL_PRIORITY_CLASS;正常:

NORMAL_PRIORITY_CLASS;低于正常:

BELOW_NORMAL_PRIORITY_CLASS;空闲:

IDLE_PRIORITY_CLASS。

nPriority是线程的相对优先级,可以是以下的值:

最高线程:

THREAD-PRIORITY-HIGHEST-2空闲:

THREAD-PRIORITY-IDLE15最低线程:

THREAD-PRIORITY-LOWEST2低于正常线程:

THREAD-PRIORITY-BELOW-NORMAL1正常线程:

THREAD-PRIORITY-NORMAL0高于正常线程:

THREAD-PRIORITY-ABOVENORMAL-1关键时间:

THREAD-PRIORITY-TIMECRITICAL-15,线程的挂起与恢复,进程中的每个线程都有挂起计数器(suspendcount)当挂起计数器值为0时,线程被执行当挂起计数器值大于0时,调度器不去调度该线程。

不能够直接访问线程的挂起计数器挂起DWORDSuspendThread(HANDLEhThread);恢复DWORDResumeThread(HANDLEhThread);原型DWORDSuspendThread(HANDLEhThread);挂起指定的线程如果函数执行成功,则线程的执行被终止每次调用SuspendThread()函数,线程将挂起计数器的值增1DWORDResumeThread(HANDLEhThread);结束线程的挂起状态来执行这个线程每次调用ResumeThread()函数,线程将挂起计数器的值减1若挂起计数器的值为0,则不会再减,线程等待,一组能使线程阻塞其自身执行的等待函数WaitForSingleObjectWaitForMultipleObject在其参数中的一个或多个同步对象产生了信号,或者超过规定的等待时间才会返回在等待函数未返回时,线程处于等待状态,线程只消耗很少的CPU时间,线程终结,在线程函数返回时,线程自动终止在线程的执行过程中终止则可调用函数:

VOIDExitThread(DWORDdwExitCode);deallocate栈;取消I/O;结束线程如果在线程的外面终止线程,则可调用下面的函数:

BOOLTerminateThread(HANDLEhThread,DWORDdwExitCode);,Win32多线程的实现,下面这个程序首先创建两个线程,当输入为1时,执行线程,否则挂起线程。

#include#includeusingnamespacestd;DWORDWINAPIFunOne(LPVOIDparam)while(true)Sleep(1000);couthello!

;,return0;DWORDWINAPIFunTwo(LPVOIDparam)while(true)Sleep(1000);coutworld!

;return0;,Win32多线程的实现(续),intmain(intargc,char*argv)intinput=0;HANDLEhand1=CreateThread(NULL,0,FunOne,(void*),线程执行和资源存取,线程之间通信的两个基本问题是互斥和同步线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应该等待,直到消息到达时才被唤醒。

线程互斥是指对于共享资源,在各线程访问时的排它性线程互斥是一种特殊的线程同步Win32线程同步的实现全局变量事件(Event)临界区(Criticalsection)互斥量(Mutex)信号量(Semaphore),Win32线程同步的实现-全局变量,全局变量进程中的所有线程均可以访问所有的全局变量,因而全局变量成为Win32多线程通信的最简单方式。

intvar;/全局变量UINTThreadFunction(LPVOIDpParam)while(var)/线程处理return0;var是一个全局变量,任何线程均可以访问和修改。

线程间可以利用此特性达到线程同步的目的。

用全局变量同步线程的例子,#include#includeusingnamespacestd;intglobalvar=false;DWORDWINAPIThreadFunc(LPVOIDpParam)coutThreadFuncendl;Sleep(200);globalvar=true;return0;问题:

主线程等待globalvar为真,如不为真则一直循环,这样占用了CPU资源如果主线程优先级高于ThreadFunc,则globalvar一直不会被置为真,intmain()HANDLEhthread=CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);if(!

hthread)coutThreadCreateError!

endl;CloseHandle(hthread);while(!

globalvar)coutThreadwhileendl;coutThreadexitendl;return0;,事件,事件(Event)是WIN32提供的最灵活的线程间同步方式用来发送命令或触发事件,安排事件执行的先后次序事件存在两种状态:

激发状态(signaledortrue)未激发状态(unsignalorfalse)事件可分为两类:

手动设置这种对象只能用程序来手动设置,在需要该事件或者事件发生时,采用SetEvent及ResetEvent来进行设置。

自动恢复一旦事件发生并被处理后,自动恢复到没有事件状态,不需要再次设置。

手动重置事件被设置为激发状态后,会唤醒所有等待的线程,而且一直保持为激发状态,直到程序重新把它设置为未激发状态。

自动重置事件被设置为激发状态后,会唤醒“一个”等待中的线程,然后自动恢复为未激发状态,原型为:

HANDLECreateEvent(LPSECURITY_ATTRIBUTESlpEventAttributes,BOOLbManualReset,BOOLbInitialState,LPCTSTRlpName);其中:

第一个参数:

与CreateThread中的第一个参数类似,是一个指向SECURITY-ATTRIBUTES结构的指针第二个参数:

代表事件的类型,是手动清除事件信号还是自动清除事件信号。

TRUE为手动清除。

第三个参数:

指明事件的初始状态第四个参数:

事件的名称,使用“事件”机制注意事项,

(1)设置事件是否要自动恢复;

(2)设置事件的初始状态;(3)如果跨进程访问事件,必须对事件命名,在对事件命名的时候,要注意不要与系统命名空间中的其它全局命名对象冲突事件对象属于内核对象进程A可以通过调用OpenEvent函数根据对象的名字获得进程B中event对象的句柄,然后对这个句柄可以使用ResetEvent、SetEvent和WaitForMultipleObjects等函数进行操作来实现一个进程的线程控制另一进程中线程的运行当程序中一个线程的运行要等待另外一个线程中一项特定的操作的完成才能继续执行时,就可以使用事件对象来通知等待线程某个条件已满足,事件机制例子,有三个线程主线程、读线程ReadThread、写线程WriteThread读线程ReadThread必须在写线程WriteThread的写操作完成之后才能进行读操作主线程必须在读线程ReadThread的读操作完成后才结束定义两个事件对象evRead,evFinishevRead由写线程WriteThread用于通知读线程ReadThread进行读操作evFinish由读线程ReadThread用于通知主线程读操作已经结束,#includestdafx.h#include#include#include#includeusingnamespacestd;HANDLEevRead,evFinish;voidReadThread(LPVOIDparam)WaitForSingleObject(evRead,INFINITE);coutReadingendl;SetEvent(evFinish);程序输出如下:

WritingReading.TheProgramisEndWaitForSingleObjectWaitsuntilthespecifiedobjectisinthesignaledstateorthetime-outintervalelapses,voidWriteThread(LPVOIDparam)coutWritingendl;SetEvent(evRead);intmain(intargc,char*argv)evRead=CreateEvent(NULL,FALSE,FALSE,NULL);evFin=CreateEvent(NULL,FALSE,FALSE,NULL);_beginthread(ReadThread,0,NULL);_beginthread(WriteThread,0,NULL);WaitForSingleObject(evFinish,INFINITE);coutTheProgramisEndendl;return0;,临界区,一种防止多个线程同时执行一个特定代码段的机制适用于多个线程操作之间没有先后顺序但要求互斥的同步多个线程访问同一个临界区的原则:

一次最多只能一个线程停留在临界区内不能让一个线程无限地停留在临界区内,否则其它线程将不能进入该临界区定义临界区变量的方法如下:

CRITICAL_SECTIONgCriticalSection;通常情况下,CRITICAL_SECTION结构体应该被定义为全局变量,便于进程中的所有线程可以方便地按照变量名来引用该结构体。

CS相关API,初始化临界区VOIDWINAPIInitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);删除临界区VOIDWINAPIDeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);进入临界区VOIDWINAPIEnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);离开临界区VOIDWINAPILeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);,使用临界区编程的一般方法是:

voidWriteData()EnterCriticalSection(例子假如一个银行系统有两个线程执行取款任务,一个使用存折在柜台取款,一个使用银行卡在ATM取款。

若不加控制,很可能账户余额不足两次取款的总额,但还可以把钱取走。

#includestdafx.h#include#include#include#includeusingnamespacestd;inttotal=100;HANDLEevFin2;CRITICAL_SECTIONcs;voidWithdrawThread1(LPVOIDparam)EnterCriticalSection(if(total-20=0),total-=20;coutYouwithdraw20endl;elsecoutYoudonothavethatmuchmoneyendl;LeaveCriticalSection(,互斥量,通常用于协调多个线程或进程的活动,通过“锁定”和“取消锁定”资源,控制对共享资源的访问。

互斥量的作用是保证每次只能有一个线程获得互斥量使用CreateMutex函数创建:

HANDLECreateMutex(LPSECURITY_ATTRIBUTESlpMutexAttributes,/安全属性,如果为0,则不可继承BOOLbInitialOwner,LPCTSTRlpName);,有关的API:

CreateMutex创建一个互斥对象,返回对象句柄;OpenMutex打开并返回一个已存在的互斥对象的句柄,使之后续访问;ReleaseMutex释放对互斥对象的占用,使之成为可用;使用互斥量的一般方法是:

voidWritedata()WaitForSingleObject(hMutex,);./dosomethingReleaseMutex(hMutex);,例子,#includestdafx.h#include#include#defineTHREAD_INSTANCE_NUMBER3LONGg_fResourceInUse=FALSE;LONGg_lCounter=0;DWORDThreadProc(void*pData)intThreadNumberTemp=(*(int*)pData);HANDLEhMutex;coutThreadProc:

ThreadNumberTempisrunning!

endl;if(hMutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,Mutex.Test)=NULL)coutOpenMutexerror!

endl;coutThreadProcThreadNumberTempgetsthemutexendl;ReleaseMutex(hMutex);CloseHandle(hMutex);return0;,续1,intmain(intargc,char*argv)inti;DWORDIDTHREAD_INSTANCE_NUMBER;HANDLEhTHREAD_INSTANCE_NUMBER;HANDLEhMutex;if(hMutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,Mutex.Test)=NULL)if(hMutex=CreateMutex(NULL,FALSE,Mutex.Test)=NULL)coutCreateMutexerror!

endl;return0;for(i=0;iTHREAD_INSTANCE_NUMBER;i+)hi=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadProc,(void*),续2,if(hi=NULL)coutCreateThreaderrorIDiendl;elsecoutCreateThread:

IDiendl;WaitForMultipleObjects(THREAD_INSTANCE_NUMBER,h,TRUE,INFINITE);coutClosetheMutexHandle!

endl;CloseHandle(hMutex);return0;,程序运行结果:

CreateThread:

1796ThreadProc:

1796isrunning!

ThreadProc1796getsthemutexCreateThread:

2140ThreadProc:

2140isrunning!

ThreadProc2140getsthemutexCreateThread:

2448ThreadProc:

2448isrunning!

ThreadProc2448getsthemutexClosetheMutexHandle!

信号量,信号量是一个核心对象,拥有一个计数器,可用来管理大量有限的系统资源当计数值大于零时,信号量为有信号状态当计数值为零时,信号量处于无信号状态创建信号量HANDLECreateSemaphore(PSECURITY_ATTRIBUTEpsa,LONGlInitialCount,LONGlMaximumCount,PCTSTRpszName/信号量的名称);释放信号量BOOLWINAPIReleaseSemaphore(HANDLEhSemaphore,LONGlReleaseCount,/信号量的当前资源数增加lReleaseCountLPLONGlpPreviousCount);打开信号量HANDLEOpenSemaphore(DWORDfdwAccess,/TheaccesstothesemaphoreobjectBOOLbInherithandle,/IfthisvalueisTRUE,processescreatedbythisprocesswillinheritthehandle.Otherwise,theprocessesdonotinheritthishandle.PCTSTRpszName);,使用信号量机制同步线程例子,#includestdafx.h#include#include#defineTHREAD_INSTANCE_NUMBER3DWORDfoo(void*pData)intThreadNumberTemp=(*(int*)pData);HANDLEhSemaphore;coutfoo:

ThreadNumberTempisrunning!

endl;if(hSemaphore=OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,Semaphore.Test)=NULL)coutOpenSemaphoreerror!

endl;coutfooThreadNumberTempgetsthesemaphoreendl;ReleaseSemaphore(hSemaphore,1,NULL);CloseHandle(hSemaphore);return0;,例子续,intmain(intargc,char*argv)inti;DWORDThreadIDTHREAD_INSTANCE_NUMBER;HANDLEhThreadTHREAD_INSTANCE_NUMBER;HANDLEhSemaphore;if(hSemaphore=CreateSemaphore(NULL,0,1,Semaphore.Test)=NULL)coutCreateSemaphoreerror!

endl;return0;for(i=0;iTHREAD_INSTANCE_NUMBER;i+)hThreadi=CreateThread(NULL,0,(LPTHREAD_START_

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

当前位置:首页 > 人文社科 > 法律资料

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2