青岛大学本科生毕业论文(设计)
2.4 并行计算技术
多任务在32位的Windows系统中,采用的是抢先式多任务,这意味着程序对CPU的占用时间是由系统决定的。系统为每个程序分配一定的CPU时间,当程序的运行超过规定时间后,系统就会中断该程序并把CPU控制权转交给别的程序。与协同式多任务不同,这种中断是汇编语言级的。程序不必调用像PeekMessage这样的函数来放弃对CPU的控制权,就可以进行费时的工作,而且不会导致系统的挂起。
例如,在Windows 3.x中,如果某一个应用程序陷入了死循环,那么整个系统都会瘫痪,这时惟一的解决办法就是重新启动机器。而在Windows 95/NT中,一个程序的崩溃一般不会造成死机,其他程序仍然可以运行,用户可以按Ctrl+Alt+Del键来打开任务列表并关闭没有响应的程序。
1、进程与线程
在32位的Windows系统中,多任务指系统可同时运行多个进程,而每个进程也可同时执行多个线程。
进程就是应用程序的运行实例。每个进程都有自己私有的虚拟地址空间,都有一个主线程.但可以建立另外的线程。进程中的线程是并行执行的,每个线程占用CPU的时间由系统来划分。
可以把线程看成是操作系统分配CPU时间的基本实体。系统不停地在各个线程之间切换,他对线程的中断是汇编语言级的。系统为每一个线程分配一个CPU时间片,某个线程只有在分配的时间片内才有对CPU的控制权。实际上,在PC机中,同一时间只有一个线程在运行。由于系统为每个线程划分的时间片很小(20ms左右),所以看上去好像是多个线程在同时运行。进程中的所有线程共享进程的虚拟地址空间,这意味着所有线程都可以访问进程的全局变量和资源。这一方面为编程带来了方便,但另一方面也容易造成冲突。虽然在进程中进行费时的工作不会导致系统的挂起,但这会导致进程本身的挂起。所以,如果进程既要进行长期的工作,又要响应用户的输入,那么他可以启动一个线程来专门负责费时的工作,而主线程仍然可以与用户进行交互。
2、基于Win 32基础上进行多线程编程的过程线程分用户界面线程和工作者线程2种。用户界面线程拥有自己的消息泵来处理界面消息,可以与用户进行交互。工作者线程没有消息泵,一般用来完成后台工作。
(1)用Win 32函数创建和中止线程
win32函数库中提供了多线程控制的操作函数,包括创建线程、中止线程、建立互斥区等。首先,在应用程序的主线程或者其他活动线程的适当地方创建新的线程。创建线程的函数如下:
HANDLE CreateThread(LPSECURITY—ATTRIBUTES lpThreadAttributes DWORD dwStackSize;
11
青岛大学本科生毕业论文(设计)
LPTHREAD—START—ROUTINE lpStartAddress。 LPVOID IpParameter DWORD dwCreationFlags; LPDW0RDIpThreadId);
其中:lpThreadAttributes指定了线程的安全属性,在Windows 95中被忽略;dwStackSize指定了线程的堆栈深度;lpStartAddress指定了线程的起始地址,一般情况为原型函数DW0RDWINAPI ThreadFunc (I PVOID);lpParameter指定了线程执行时传送给线程的32位参数,即上面函数的参数;dwCreationFlags指定了线程创建的特性;lpThreadld指向一个DWORD变量,可返回线程ID值。如果创建成功则返回线程的句柄,否则返回NUII。创建了新的线程后,则该线程就开始启动执行了。如果在dwCreationFlags中用了CREATE—SUSPENDED特性,那么线程并不马上执行,而是先挂起,等到调用ResumeThread后才开始启动线程,在这个过程中可以调用函数:BOOI SetThread Priority (HANDI E hThread,int nPriority)来设置线程的优先权。当线程的函数返回后,线程自动中止。如果在线程的执行过程中中止的话,则可调用函数:VOID Exit Thread(DWORD dwExit Code);如果在线程的外面中止线程的话,则可调用下面的函数:BOoI TerminateThread (HANDI E hThread,DWORD dwExitCode)。但应注意:该函数可能会引起系统不稳定,而且线程所占用的资源也不释放。因此,一般情况下,建议不要使用该函数。如果要中止的线程是进程内的最后一个线程,则在线程被中止后相应的进程也应中止。
3、用Win 32函数控制线程对共享资源的访问在线程体内,如果该线程完全独立,与其他的线程没有数据存取等资源操作上的冲突,则可按照通常单线程的方法进行编程。但是,在多线程处理时情况常常不是这样,线程之间经常要同时访问一些资源。例如,一个线程负责公式计算,另一个线程负责结果的显示,两个线程都要访问同一个结果变量。这时如果不进行冲突控制的话,则很可能显示的是不正确的结果。对共享资源进行访问引起冲突是不可避免的,但可用以下办法来进行操作控制:
(1)通过设置线程的互斥体对象,在可能冲突的地方进行同步控制;首先,建立互斥体对象,得到句柄:HANDLE CreateMutex();然后,在线程可能冲突区域的开始 (即访问共享资源之前),调用WaitForSingleObject将句柄传给函数,请求占用互斥体对象:dwWaitResult =WaitForSingleObject(hMutex,5000L);共享资源访问完后,释放对互斥体对象的占用:ReleaseMutex (hMutex);互斥体对象在同一时刻只能被一个线程占用。当互斥体对象被一个线程占用时,若有另一线程想占用他,则必须等到前一线程释放后才能成功。
(2)设置信号
在操作共享资源前,打开信号;完成操作后,关闭信号。这类似于互斥体对象的处理。首先,创建信号对象:HANDLE CreateSemaphore();或者打开一个信号对象:HANDI E OpenSemaphore();然后,在线程的访问共享资源之前调用WaitForSingleObject。共享资源访问完后,释放对信号对象的占用:ReleaseSemaphore();信号对象允许同时对多个线程共享资源的访问,在创建对象时指定最大可同时访问的线程数。当一个线程申请访问成功后,信号
12
青岛大学本科生毕业论文(设计)
对象中的计数器减1;调用ReleaseSemaphore函数后,信号对象中的计数器加1。其中,计数器值≤创建时指定的最大值。利用信号对象,不仅可以控制共享资源的访问,还可以在应用的初始化时候使用。假定一个应用在创建一个信号对象时,将其计数器的初始值设为0,这样就阻塞了其他线程,保护了资源。待初始化完成后,调用ReleaseSemaphore函数将其计数器增加至最大值,进行正常的存取访问。
(3)利用事件对象的状态,进行线程对共享资源的访问用ResetEvent函数设置事件对象状态为不允许线程通过;用SetEvent函数设置事件对象状态为可以允许线程通过。事件分为手工释放和自动释放。如果是手工释放,则按照上述2个函数处理事件的状态;如果是自动释放,则在一个线程结束后,自动清除事件状态,允许其他线程通过。
(4)设置排斥区
在排斥区中异步执行时,他只能在同一进程的线程之间共享资源处理。虽然此时上面介绍的3种方法均可使用,但是,使用排斥区的方法则使同步管理的效率更高;先定义一个CRITICAl 一SECTlON结构的排斥区对象,在进程使用之前先对对象进行初始化,调用如下函数:VO1D Initialize Critical Section(LPCRlTlCAL—SECTlON);当一个线程使用排斥区时,调用函数:EnterCriticalSection或者TryEnterCriticalSection;当要求占用、退出排斥区时,调用函数:LeaveCriticalSection。释放对排斥区对象的占用,供其他线程使用。互斥体对象、信号对象和事件对象也可以用于进程间的线程同步操作。
在用win32函数创建了对象时,可以指定对象的名字,还可以设置同步对象在子进程的继承性。创建返回的是HANDLE句柄,可以用函数DuplicateHandle来复制对象句柄,这样每个进程都可以拥有同一对象的句柄,实现进程之间的线程同步操作。另外,在同一进程内,可以用OpenMutex,OpenSemaphore和OpenEvent来获得指定名字的同步对象的句柄。排斥区异步执行的线程同步方法只能用于同一进程的线程之问共享资源处理,但是这种方法的使用效率较高,而且编程也相对简单一些。在Visual C++中,除了利用Win32函数进行多线程同步控制外,如果用到了MFC类库,则可利用已经封装成C++类结构的同步对象,使编程更加简捷。
2.5 OpenMP编程模型
2.5.1 OpenMP介绍
OpenMP使用fork-join(见图2-1)并行机制,程序开始串行执行,此时只有一个主线程,然后在遇到用户定义的并行区域时创建出一组线程。在并行区域之内,多个线程可以执行相同的代码块,或使用工作共享结构体并行执行不同的任务。
13
青岛大学本科生毕业论文(设计)
主线程 并行区域 图2-1 fork-join并行机制
OpenMP由指导命令、环境变量和运行库组成,见图2-2
#1/bin/ksh # Shell-Script f90 –openmp test_f90 export OMP_THREADS*4 a.out Environment variables directives (special comment lines) ! Source file test_f90 Program main Intager omp_get_thread_num ! $omp parallel print *, ‘me: ‘ omp_get_num() ! $omp and parallel end program 图2-2 OpenMP组成
runtime library me:0 me:3 me:2 me:1
通过在串行程序里加入适当的指导命令和运行库函数,就可以把串行并行化,这种增量并行的模式使得开发并行程序变得很容易。
OpenMP结构如图2-3所示
user shell OpenMP program envronment variables directives runtime functions OpenMP runtime system operating system-theads 图2-3 OpenMP体系结构
14
青岛大学本科生毕业论文(设计)
2.5.2 OpenMP指导命令流程
OpenMP主要包含如图所示的指导命令
parallel begin loop begin barrier flush single begin parallel end loop end single end master begin critical begin ordered begin master end critical end orderd end sections begin section begin section begin section end section end sections end 我们用流程图的形式把OpenMP指导指令的特点描绘出来,对于parallel指导命令包含的代码段,线程组中所有的线程都要执行,对于loop指导命令包含的代码段,可能只有部分线程执行,右侧的方向线表示有的线程没有执行完这段代码,左侧的方向线刻画出循环的特点,执行完一次迭代后,如果还有任务,从循环开始处执行下一次迭代;barrier指导命令表示所有线程在此处同步,然后再执行接下来的语句,barrier指导命令没有包含代码段;flush指导命令后面加上需刷新的共享变量,所以在图中没有画出中间的箭头,即表示不包含代码段;single指导命令所包含的代码段只由一个线程组执行,别的线程跳过这段代码,如果single指
图2-4 OpenMP指导命令流程
图
15
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库语音识别论文(4)在线全文阅读。
相关推荐: