Windows 95多线程间同步事件的节制要领
当前位置:以往代写 > C/C++ 教程 >Windows 95多线程间同步事件的节制要领
2019-06-13

Windows 95多线程间同步事件的节制要领

Windows 95多线程间同步事件的节制要领

副标题#e#

摘要:在Windows 95中所有的应用措施实际上都以是线程的方法运行的。在设计多线程应用措施中有时必需在线程之间保持必然的同步干系,才气利用户可以或许对独立运行的线程举办有效的节制。为此本文在扼要先容Windows 95中线程的观念及其建设要领后,提出了一种在多线程之间操作 event工具实现事件同步的节制要领。最后还先容了在差异应用措施之间举办同步事件节制的要领,这种要领使得差异应用措施举办彼此间的同步事件节制变得很简朴。

要害词:Windows95 线程

同步事件 event

工具 Win32

一, 引言

Windows 95是一个多任务、多线程的操纵系统,个中的每一个应用措施都是一个历程(process)。历程可以建设多个并发的线程(thread),同时历程也以主线程(primarythread)的形式被系统调治。所谓的线程是系统调治的一个根基单元, 在措施中线程是以函数的形式呈现的,它的代码是历程代码的一部门,并与历程及其派生的其它线程共享历程的全局变量和文件打开表等公用信息。主线程雷同于UNIX系统中的父历程,线程则雷同于子历程。主线程也是一个线程,称作主线程仅仅是为了和它建设的线程区别开来。每个线程都相对付主线程而独立运行,为了使得线程能对用户的控建造出响应,必需节制线程的运行,好比用户可暂停、终止一个线程的运行或改变线程运行的条件等。并且在用户节制与线程运行之间有时应该有必然的同步节制干系,以担保用户对线程的有效节制。线程可以按照差异的条件对用户的控建造出差异的响应。为了实现上述目标必需利用系统提供的同步工具(Synchronization Object),如event工具。 编写多线程应用措施必需利用Win32 API。

二, 线程的建设要领

挪用Win32 API中的CreateThread函数建设线程。hThread=CreateThread(NULL,0,&TEventWindow::ThreadFunc,this,0,&hThreadId);第一个参数设定线程的安详属性,因其仅用于Windows NT,故不设定。第二个参数为0指定线程利用缺省的仓库巨细。第三个参数指定线程函数,线程即从该函数的进口处开始运行,函数返回时就意味着线程终止运行。第四个参数为线程函数的参数,可以是指向任意数据范例的指针。第五个参数设定线程的生成符号。hThreadId存放线程的标识号。线程函数如下界说,上述的 this参数是指向线程所属窗口的句柄指针,通过thrdWin参数传送过来,操作这个指针再挪用相应的LoopFunc函数,线程的详细事务都在这个函数中执行。


#p#副标题#e#

DWORD _stdcall TEventWindow::ThreadFunc(void *thrdWin){
return STATIC_CAST(TEventWindow*,thrdWin)->LoopFunc( );
}

三, 线程的同步事件节制要领

Windows 95提供两种根基范例的系统工具,一种是互相互斥的工具,用来协调会见数据,如 mutex工具;一种是事件同步工具,用来发送呼吁或触发事件,布置事件执行的先后序次,如 event工具。系统工具在系统范畴内有效,它们都具有本身的安详属性、会见权限和以下两种状态中的一种:Signaled和nonSignaled。对付event工具挪用SetEvent函数可将其状态设为Signaled,挪用ResetEvent函数则可将其状态设为nonSignaled。演示措施中的线程在一个大轮回中不绝地将运行功效显示出来,当用户要封锁窗口时线程才终止运行。不外必需在窗口封锁之前先终止线程的运行,不然线程运行的功效将会显示在屏幕的其他处所,所以有须要在线程竣事与封锁窗口这两个事件之间成立起同步干系。为此在TEventWindow类的结构函数中建设两个event工具,用来实现事件同步。hCloseEvent=CreateEvent(0,FALSE,FALSE,0); hNoCloseEvent=CreateEvent(0,FALSE,FALSE,0);第二个参数为FALSE 暗示建设的是一个自动event工具,第三个参数为FALSE暗示工具的初始状态为nonSignaled,第四个参数为0暗示该工具没有名字。在TEventWindow类的结构函数中还同样建设hWatchEvent和hNtyEvent工具,初始状态都为nonSignaled。用户要封锁窗口时,措施首先挪用CanClose 函数,在该函数中配置hCloseEvent工具的状态为Signaled,操作这个要领来通知线程,要求线程终止运行。然后主线程挪用函数WaitForMultipleObjects(该函数以下简称wait函数 ),wait函数先判定工具hThread和hNoCloseEvent中任意一个的状态是否为Signaled, 假如都不是就堵塞主线程的运行,直到上述条件满意;假如有一个工具的状态为Signaled,wait函数就返回,不再堵塞主线程。假如工具是自动event工具,wait函数在返回之前还会将工具的状态设为nonSignaled。wait函数中的参数FALSE暗示不要求两个工具的状态同时为Signaled,参数-1暗示要无限期地期待下去直到条件满意,参数2暗示SignalsC数组中有两个工具。在Windows 95中线程也被看作是一种系统工具,同样具有两种状态。线程运行时其状态为nonSignaled,假如线程终止运行,则其状态被系统自动设为Signaled( 可以通过线程的句柄hThread获得线程状态),此时wait函数返回0,暗示第一个工具满意条件,于是CanClose返回TRUE暗示窗口可以封锁;假如线程不能满意终止运行的条件,就配置hNoCloseEvent 工具的状态为Signaled,此时wait函数返回1,暗示第二个工具满意条件,于是CanClose返回FALSE暗示窗口临时还不能封锁。

#p#副标题#e#
#p#分页标题#e#

BOOL TEventWindow::CanClose(){
HANDLE SignalsC[2]={hThread,hNoCloseEvent};
SetEvent(hCloseEvent);
if(WaitForMultipleObjects(2,SignalsC,FALSE,-1)==0) return TRUE;
else return FALSE;
}

另一个用户节制的例子是,用户使主线程暂停运行直到线程满意某种条件为止。好比用户选择“Watch”菜单后,主线程挪用如下函数开始对线程的运算数据举办监测。 首先配置hWatchEvent工具的状态为Signaled,以此来通知线程, 主线程此时已进入期待状态并开始对数据举办监测,然后主线程挪用wait函数期待线程的回应。线程在满意某个条件后就配置hNtyEvent工具的状态为Signaled,使主线程竣事期待状态,继承运行。

void TEventWindow::CmWatch(){
SetEvent(hWatchEvent);
WaitForSingleObject(hNtyEvent,-1);
::MessageBox(GetFocus(),"线程已切合条件,主线程继承运行!","",MB_OK);
}

线程函数所挪用的LoopFunc是一个大轮回,它不绝地判定同步工具的状态,并按照这些工具的状态执行相应的操纵,这些工具在数组SignalsL中列出。在这个数组中各元素的分列顺序是很重要的,前两个工具别离对应两种差异的用户节制事件,通过判定工具的状态可以知道产生的是哪一种用户节制。只有当前面两个工具的状态都不是Signaled时才会判定第三个工具的状态,这样一方面担保线程能检测到所有的用户节制事件,另一方面又担保了在不产生用户节制事件时线程也能继承运行。为此特地在TEventWindow类的结构函数中建设的工具hNoBlockEvent的状态始终为Signaled。

hNoBlockEvent=CreateEvent(0,TRUE,TRUE,"MyEvent");

#p#副标题#e#

第二个参数为TRUE暗示建设的是一个手工event工具, 其状态是不会被wait函数所改变的,除非显式地挪用ResetEvent函数。第三个参数为TRUE暗示工具初始状态为Signaled,第四个参数界说了该工具的名字为“MyEvent”。LoopFunc函数挪用wait函数,假如检测到hCloseEvent的状态为Signaled, 此时wait函数返回0,线程知道用户要封锁窗口了,就判定线程是否可以终止,条件是iCount>100,假如满意终止条件LoopFunc函数就返回,实际上就终止了线程的运行;假如不满意条件线程就配置 hNoCloseEvent工具的状态为Signaled,让主线程知道线程临时还不能终止。由于hCloseEvent是自动event工具,所以wait函数返回0时还会将工具hCloseEvent的状态配置为nonSignaled,这样在第二次轮回时,wait函数就不会判定出hCloseEvent工具的状态为Signaled,制止了线程错误地再次去判定是否会满意终止条件。假如wait函数检测到工具hWatchEvent的状态为Signaled,此时wait函数返回1,线程知道主线程已进入期待状态并在对数据举办监测,就配置变量bWatch的值为TRUE。假如前面的两个事件都未产生,则前面两个工具的状态都为nonSignaled,于是wait函数就检测第三个工具的状态, 由于第三个工具hNoBlockEvent 的状态始终为Signaled,所以线程就无阻碍地继承运行下去,将变量iCount不绝加一,当变量大于200时,假如bWatch为TRUE,就配置hNtyEvent的状态为Signaled,从而使主线程遏制期待,继承运行。

DWORD TEventWindow::LoopFunc(){
HANDLE SignalsL[3]={hCloseEvent,hWatchEvent,hNoBlockEvent};
static BOOL bWatch=false;int dwEvent;
while(1){
dwEvent=WaitForMultipleObjects(3,SignalsL,FALSE,-1);
switch(dwEvent){
case 0: if(iCount>100) return 0;
else SetEvent(hNoCloseEvent);
break;
case 1: bWatch=TRUE;break;
case 2: ++iCount;
if(bWatch && iCount>200) SetEvent(hNtyEvent);
break;
}
}
}

#p#副标题#e#

四, 历程间的多线程同步事件节制要领

由于event工具是系统范畴内有效的,所以另一个历程(即一个应用措施,自己也是一个线程)可挪用OpenEvent函数,通过工具的名字得到工具的句柄, 但工具必需是已经建设的,然后可将这个句柄用于ResetEvent、SetEvent和WaitForMultipleObjects等函数中。这样可以实现一个历程的线程节制另一历程生成的线程的运行。如下面的语句就是通过工具名字“MyEvent”得到了上面历程生成的hNoBlockEvent工具的句柄,再利用这个句柄将工具状态设为nonSignaled。在上述的 LoopFunc函数中由于该工具的状态已经改变,使得上面的线程暂停运行。

HANDLE hEvent=OpenEvent(EVENT_ALL_ACCESS,true,"MyEvent");

ResetEvent(hEvent);

#p#分页标题#e#

OpenEvent函数的第一个参数暗示函数的挪用线程对event工具的会见权限,好比让线程拥有工具所有的会见权限,就选参数EVENT_ALL_ACCESS,这样线程就能用ResetEvent函数改变工具的状态;参数true暗示由这个历程派生的子历程可以担任该句柄;最后一个参数指出了event工具的名字。用下面的语句配置工具hNoBlockEvent的状态为Signaled,就可以使线程继承运行,如SetEvent(hEvent)。

历程不再利用该句柄时尽可以用CloseHandle函数封锁工具句柄,但对付同一个event工具而言,因为它大概还在此外线程中被利用,所以只有在它的所有被引用的句柄都封锁后工具才会被系统释放,文中提到的所有 event工具在主线程和线程之间以及在差异的历程之间所起的节制浸染如图1所示:

① ┌───────┐ ①:封锁窗口
┌──→─┤ hCloseEvent ├───┐ ②:对上面事件的回响
│ └───────┘ │ |
│ ┌───────┐ ↓ | 暂停/规复线程的运行
│ │ hThread 或 │②┌─┴─┐  ┌───────┐ ┌───┐
┌─┴─┐ ┌┤hNoCloseEvent ├←┤ 线程 ├←┤hNoBlockEvent ├←┤历程 2│
│主线程├←┘└───────┘ └┬─┬┘  └───────┘ └───┘
│/历程1├→┐┌───────┐ ↑ │ |差异历程之间
└─┬─┘⑴└┤ hWatchEvent ├──┘ │ |的地点边界
↑ └───────┘ │
│ ┌───────┐ │ ⑴:监测数据
└────┤ hNtyEvent ├←───┘ ⑵:线程满意监测条件
└───────┘⑵

图1 event工具在多线程间同步事件节制中的浸染

五, 竣事语

多线程编程技能在多媒体、网络通讯、数学计较和及时节制方面有着很辽阔的应用前景。虽然在实际编程中环境往往是很巨大的,这时应留意的是如何将任务精确地分别成可并发的线程以及象文中提到的SignalsL数组中元素的分列顺序等问题。本文所讲内容对付在Windows NT或在某些支持多线程的UNIX系统中设计多线程应用措施也是有所辅佐的。

    关键字:

在线提交作业