《多线程并行编程模型.ppt》由会员分享,可在线阅读,更多相关《多线程并行编程模型.ppt(53页珍藏版)》请在三一办公上搜索。
1、多核编程,大连东软信息学院 多核课程组,课程目录,第2单元主要内容,2.1 Windows API 多线程编程2.2 OpenMP 多线程编程,第4次课程主要内容,2.1 Windows API 多线程编程,创建,终止线程的方法 利用同步对象协调线程的运行和内存访问资源互斥数据共享,目标,引例,输出Hello Thread,DWORD WINAPI helloFunc(LPVOID arg)printf(“Hello Threadn”);return 0;main()HANDLE hThread=CreateThread(NULL,0,helloFunc,NULL,0,NULL);WaitFo
2、rSingleObject(hThread,INFINITE);,引例,定义:内核对象是由操作系统内核分配的,只能由内核访问的一个内存块,用来供系统和应用程序使用和管理各种系统资源。线程对象、事件对象、文件对象、文件映射对象、作业对象、互斥量、管道对象、进程对象、信标对象和等待计时器对象等。对象都是通过调用函数来创建的。例如CreateThread(),内核对象,HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,/在系统中使用方法进程高级设置 DWORD dwStackSize,/线程堆栈大小 LPTHREAD_START
3、_ROUTINE lpStartAddress,/函数指针,指向实际运行的代码 LPVOID lpParameter,/参数指针 DWORD dwCreationFlags,/设置标志 LPDWORD lpThreadId);/线程ID,创建线程,LPTHREAD_START_ROUTINE,DWORD WINAPI MyThreadStart(LPVOID p);,创建线程,BOOL CloseHandle(HANDLE hObject);,线程的终止,#include#include DWORD WINAPI helloFunc(LPVOID arg)printf(“Hello Threa
4、dn”);return 0;main()HANDLE hThread=CreateThread(NULL,0,helloFunc,NULL,0,NULL);,What Happens?,主线程执行太快,子线程没有执行,例子:线程的创建,#include#include BOOL threadDone=FALSE;DWORD WINAPI helloFunc(LPVOID arg)printf(“Hello Threadn”);threadDone=TRUE;return 0;main()HANDLE hThread=CreateThread(NULL,0,helloFunc,NULL,0,NU
5、LL);while(!threadDone);/wasted cycles!,Not a good idea!,线程的等待,原型:等待一个线程,DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);,线程的等待,引例,输出:Hello ThreadHello ThreadHello ThreadHello Thread,原型 The WaitForMultipleObjects()function has the following parameters:nCountlpHandlesfWaitAlldwMilliseco
6、nds,DWORD WaitForMultipleObjects(DWORD nCount,CONST HANDLE*lpHandles,/array BOOL fWaitAll,/wait for one or all DWORD dwMilliseconds);,Wait for all:fWaitAll=TRUEWait for any:fWaitAll=FALSE,多个线程的等待,const int numThreads=4;DWORD WINAPI helloFunc(LPVOID arg)printf(“Hello Threadn”);return 0;main()HANDLE h
7、ThreadnumThreads;for(int i=0;i numThreads;i+)hThreadi=CreateThread(NULL,0,helloFunc,NULL,0,NULL);WaitForMultipleObjects(numThreads,hThread,TRUE,INFINITE),引例解决方案,问题思考,输出:Hello Thread 0Hello Thread 1Hello Thread 2Hello Thread 3,DWORD WINAPI threadFunc(LPVOID pArg)int*p=(int*)pArg;int myNum=*p;printf(“
8、Thread number%dn”,myNum);./from main():for(int i=0;i numThreads;i+)hThreadi=CreateThread(NULL,0,threadFunc,输出的结果是什么?,问题解决?,下面的表将说明出现问题的原因,分析,在多线程应用将遇到的问题,多线程问题数据竞争,数据竞争Read/Write 竞争Write/Write 竞争,多线程问题数据竞争,如何解决数据竞争,在多线程应用中避免数据竞争的两种方法将变量的应用范围具体到每一个线程内部变量声明在线程内线程本地存储Thread Local Storage(TLS)以临界的方法控制并行
9、访问同步对象Critical section 临界区Mutex 互斥Semaphore 信号量Event 事件,DWORD WINAPI threadFunc(LPVOID pArg)int myNum=*(int*)pArg);printf(“Thread number%dn”,myNum);.for(int i=0;i numThreads;i+)tNumi=i;hThreadi=CreateThread(NULL,0,threadFunc,本地存储,编程实现,1100=?,Critical section 临界区Mutex 互斥Semaphore 信号量Event 事件,同步对象,临界区
10、,特点轻量级常用非内核对象,临界区,相关接口 CRITICAL_SECTION cs/定义临界区 IntializeCriticalSection(&cs)/初始化临界区DeleteCriticalSection(&cs)/注销临界区,void WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);,void WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);,EnterCriticalSection(&cs)/进入临界区L
11、eaveCriticalSection(&cs)/退出临界区当临界区有其他线程时,线程将被阻塞不返回。当临界区没有线程时将返回,void WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);,void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);,临界区,#define NUMTHREADS 4CRITICAL_SECTION g_cs;/为什么定义成全局变量int g_sum=0;DWORD WINAPI threadFunc
12、(LPVOID arg)int mySum=bigComputation();EnterCriticalSection(,指导案例:临界区,编程实现,11000000=?,特点内核对象被一个线程拥有进程、线程间的同步 跨进程进行同步访问。为获得一个信号量要进行内核调用,开销大相关接口:CreateMutex()/创建互斥量WaitForSingleObject()/等待、加锁ReleaseMutex()/解锁,互斥量,实验项目,完成Windows*Threads多线程编程实验,项目二:临界区实验。,事件多用于下列情况:通知计算完成通知数据可用通知消息就绪等待事件的接口:WaitForSingl
13、eObject()/一个事件WaitForMultipleObjects()/多个事件事件的两种类型:Auto-reset events/自动重置事件Manual-reset events/人工重置事件,事件,警告:慎用 WaitForMultipleObjects()等待所有的事件,事件的两种类型,bManualReset TRUE:人工重置事件FALSE:自动重置事件 bInitialState TRUE:激发态FALSE:未激发态,HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL bManualReset,/确
14、定重置方式 BOOL bInitialState,/确定事件的初始状态 LPCSTR lpName);/事件名称,事件的创建,SetEvent()ResetEvent(),BOOL SetEvent(HANDLE event);,BOOL ResetEvent(HANDLE event);,事件的设置和重置,HANDLE hObj 2;/0 is event,1 is thread,DWORD WINAPI threadFunc(LPVOID arg)BOOL bFound=bigFind();if(bFound)SetEvent(hObj0);/满足激发条件 bigFound();moreB
15、igStuff();return 0;,指导案例:事件,.hObj0=CreateEvent(NULL,FALSE,FALSE,NULL);hObj1=CreateThread(NULL,0,threadFunc,NULL,0,NULL);DWORD waitRet=WaitForMultipleObjects(2,hObj,FALSE,INFINITE);switch(waitRet)case WAIT_OBJECT_0:printf(found it!n);WaitForSingleObject(hObj1,INFINITE);case WAIT_OBJECT_0+1 printf(thr
16、ead donen);break;default:printf(“wait error:ret%un,waitRet);break;,指导案例:事件,.hObj0=CreateEvent(NULL,FALSE,FALSE,NULL);hObj1=CreateThread(NULL,0,threadFunc,NULL,0,NULL);/*Do some other work while thread executes search*/DWORD waitRet=WaitForMultipleObjects(2,hObj,FALSE,INFINITE);switch(waitRet)case WA
17、IT_OBJECT_0:printf(found it!n);WaitForSingleObject(hObj1,INFINITE);case WAIT_OBJECT_0+1;printf(thread donen);break;default:printf(“wait error:ret%un,waitRet);break;,指导案例:事件,特点:允许一个或者更多的线程进入临界区用于与多个可用资源的访问对信号量的操作可以概括为以下两种操作:Wait P(s):s=s-1Post V(s):s=s+1,信号量,原型:0 0.,HANDLE CreateSemaphore(LPSECURITY_
18、ATTRIBUTES lpEventAttributes,LONG lSemInitial,/初始化的值 LONG lSemMax,/最大值 LPCSTR lpSemName);,信号量的创建,WaitForSingleObject()/wait操作如果semaphore count=0,如果 semaphore count 0,执行信号量减-1操作后返回.post操作,BOOL ReleaseSemaphore(HANDLE hSemaphore,LONG cReleaseCount,LPLONG lpPreviousCount);,Wait和Post操作,常用于:控制对有限数据空间的访问限
19、制对一段给定代码的线程访问数量控制对有限资源的访问当信号量定义为1时,类似于互斥量,信号量的使用,HANDLE hSem1,hSem2;FILE*fd;int fiveLetterCount=0;,main()HANDLE hThreadNUMTHREADS;hSem1=CreateSemaphore(NULL,1,1,NULL);/Binary semaphore hSem2=CreateSemaphore(NULL,1,1,NULL);/Binary semaphore fd=fopen(“InFile”,“r”);/Open file for read for(int i=0;i NUM
20、THREADS;i+)hThreadi=CreateThread(NULL,0,CountFives,NULL,0,NULL);WaitForMultipleObjects(NUMTHREADS,hThread,TRUE,INFINITE);fclose(fd);printf(“Number of five letter words is%dn”,fiveLetterCount);,指导案例:信号量,DWORD WINAPI CountFives(LPVOID arg)BOOL bDone=FALSE;char inLine132;int lCount=0;while(!bDone)WaitF
21、orSingleObject(hSem1,INFINITE);/access to input bDone=(GetNextLine(fd,inLine)=EOF);ReleaseSemaphore(hSem1,1,NULL);if(!bDone)if(lCount=GetFiveLetterWordCount(inLine)WaitForSingleObject(hSem2,INFINITE);/update global fiveLetterCount+=lCount;ReleaseSemaphore(hsem2,1,NULL);,指导案例:信号量,综合项目达成,问题描述从一单精度浮点数串
22、中找出乘积最大的连续的4个浮点数。例如在下列浮点数串1.0,2.0,3.0,4.0,5.0,6.0,5.0,3.0,3.0,2.0,9.0,1.0,2.0找到4.0,5.0,6.0,5.0.采用Windows多线程API语言编写并行程序完成本项目。,HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadI
23、d);DWORD WINAPI MyThreadStart(LPVOID p);BOOL CloseHandle(HANDLE hObject);DWORD WaitForMultipleObjects(DWORD nCount,CONST HANDLE*lpHandles,BOOL fWaitAll,DWORD dwMilliseconds);,总结,CRITICAL_SECTION cs IntializeCriticalSection(&cs)DeleteCriticalSection(&cs)EnterCriticalSection(&cs)LeaveCriticalSection(&
24、cs),总结,HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL bManualReset,BOOL bInitialState,LPCSTR lpName);BOOL SetEvent(HANDLE event);BOOL ResetEvent(HANDLE event);,总结,HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpEventAttributes,LONG lSemInitial,/初始化的值 LONG lSemMax,/最大值 LPCSTR lpSemName);WaitForSingleObject()BOOL ReleaseSemaphore(HANDLE hSemaphore,LONG cReleaseCount,LPLONG lpPreviousCount);,总结,本章小结,并行化程序开发流程三个部分六个阶段分解模式数据分解任务分解数据竞争临界区同步互斥,谢谢!,