注意:此文只是讲线程间的同步,其它同步不涉及。windows
线程同步是个好话题,由于写线程常常会遇到,因此就写写本身知道的东西。 数组
D里面,同步(特指线程同步)从线程的角度来分,有几种状况:函数
1:主线程与工做线程的同步学习
2:工做线程与主线程的同步spa
3:工做线程之间的同步。线程
同步,嗯,直白点讲,或能够说成是:A线程怎么通知B线程去作某某事,或者说某事须要:如何控制某一时间段内,A能作,B不能作(互斥)。指针
因此,手段很重要,也就有了API,也就有了方法:code
1:lock(CriticalSection)orm
2:Event/Mutex/Semaphore + WaitFor
3:PostMessage/SendMessage/PostThreadMessageblog
简单的作一下介绍,可能不详细,具体请查看MSDN
一:锁:临界锁:CriticalSection
一般咱们所说的锁,通常状况下都指这个临界锁CS。
在N线程间,对某数据,某资源的排它性, 互斥性的访问,相似以下:
lock.enter();
inc(value);
lock.leave();
CS相对于上述其它类型的同步,是最快的同步操做了。
不过,锁有N种,什么SWRLock, spinlock。。。某些场合用某种锁也是有分别的,须要自行查资料学习(学习不深,就不误人子弟了)
二: Event/Mutex/Semaphore + WaitFor
这类同步,是信号灯相似的同步
1:Event: 事件信号
API:CreateEvent, SetEvent, ResetEvent + WaitFor
建立一event,而后经过waitfor函数检查是否有信号,有则进入并作处理,无则等待。
2:Mutex:互斥信号
API:CreateMutex, ReleaseMutex + WaitFor
跟event雷同,而后建立mutex,而后用Waitfor进行检查是否该资源是否可占用,有则进入并作处理,处理完relaseMutex...
3:Semaphore:信号量
API: CreateSemaphore, ReleaseSemaphore + WaitFor
这个跟上述两个,有点区别:在建立的时候,指定资源能够有N个,WaitFor时,若是还有资源,则返回有信号,表示占用了一个资源,处理完,必须使用ReleaseSemaphore,将资源返回。
请注意:
以上三种信号,在使用WaitFor,并返回WAIT_OBJECT_0后,表示占用了该资源,处理完成后,须要对应的API进行释放
event在手动管理(建立时的参数)的状况下,Waitfor不会自动占用资源。
4:Waitfor函数
WaitForSingleObject 或 WaitForMultipleObjects 或 MsgWaitForMultipleObjects。。。
WaitFor是一组相似的等待事件触发的函数组,具体请查看:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms687069(v=vs.85).aspx
通常用用WaitForSingleObject就行了。
此类同步,应该叫触发类,事件类,通知类的同步。
如:AB线程经过共享一个event/mutex/semaphore,而后线程A置有信号,线程B进行Waitfor等待,达到同步机制。
注意点:
1: event: 不要超过N>2个线程进行对此操做,通常是工做线程中public出来event,
或由该线程自己public一方法去操做置有信号,线程内部自己进行waitfor操做。
2:mutex:同上,我通常用于互斥进程。
3:semaphore: 通常由一个管理者/调度者生成semaphore,而后分配给N个子线程
由于它能够有多个资源(自定义)可占用,有点像XX池资源,但固定只有N个资源,用完只能等待其它线程的返回。
三:PostMessage/SendMessage/PostThreadMessage
这几个应该很熟悉才对,发送消息到某个线程队列中。
Post/Send是工做/次线程发送消息到主线程消息队列。
PostThreadMessage是线程间的消息发送,或主线程发送消息到其它工做线程。
请注意:
PostMessage/PostThreadMessage是有可能发送失败,若是发送的是指针内存,且“发送后无论”,则会产生内存泄露。
------------------------------------------------------------------------------------
------------------------------------------------------------------------------------
OK,有了以上介绍,同步就是件很容易的事
1:同步:主线程->工做线程:
a: 队列+lock
主线程产生大量工做,且须要工做线程处理,请使用此法
b: event, semaphore置有信号,其它数据,用线程参数赋值(得当心了)(mutex我比较少用)
主线程某条件成熟,不肯定周期,通知类的须要让工做线程工做,请用此法。
c: 使用PostThreadMessage,将须要的东西用参数带上
请查看VCL代码:SConnect.pas::TTransportThread.Execute
里面有Event+PostThreadMessage的处理示例,写的:你会不禁自主的说声赞。(我将代码抽出,请查看:示例代码B)
2:同步:工做线程->主线程:
a: TThread.Synchronize(xxx)
随着D版本越高,TThread提供的同步函数愈来愈多,也愈来愈简单,居家首选。
b: 使用Post/SendMessage,带上对应的Handle(Form?Application?)
我喜欢PostMessage,发送后不用管。
我喜欢SendMessage/SendMessageTimeout,至关于同步操做主线程的组件后,继续下一步。
d: 队列+lock
在工做线程要产生大量数据,且要主线程处理时,推荐用此法,而不是上述两法。
c: event, semaphore置信号,通知主线程某条件成熟了...
这里,不推荐用此法同步,很简单WaitFor通常用于阻塞式操做,在工做线程用此法居多,而不是在主线程,
虽然能够将WaitFor的timeout=0,以非阻塞操做,但此法不推荐。
3:同步:工做线程间的同步
a: 首选:队列+lock
不为啥,快且简单。队列的push&pop,再加上lock,操做起来简单快捷。
b: event,semaphore进行互斥访问
通知性的,资源锁定类型,能够用它,其实,我更以为A法更好些,不过有些场合也是有用处的。
c: PostThreadMessage不建议,但也是个法子。
若是你想学习一下线程是怎么处理消息的,它其实也是简单的。
请查看:示例代码A
这里不作代码分析,只是说一下线程同步方法及一些适用场合。
其实D.VCL中,里面的同步法子甚多,好比TThread.Synchronize就颇有意思。
没了。
示例代码A
procedure TMyThreadA.Execute; var msg: TMsg; begin // 若是使用Peek进行取消息,在取前,必须使用下列函数,进行建立消息队列,才能使用。 // 若是使用GetMessage,则不须要,但问题是GetMessage会阻塞线程,直到收到消息。 // so,请自行选择。 PeekMessage(msg, 0, 0, 0, PM_NOREMOVE); while not Terminated do try // 从队列取消息 while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do begin case msg.message of WM_MYMSG_0: ; // do my msg WM_MYMSG_1: ; // do my msg1 ... else DispatchMessage(msg); end end; // 通常不建议使用WaitMessage,建议使用sleep(5) // 由于退出时,你得发消息,不然Thread.Terminate()线程退不出来 Sleep(5); except // todo: except end; end;
示例代码B:
procedure TMyThreadB.Execute; var msg: TMsg; begin PeekMessage(msg, 0, 0, 0, PM_NOREMOVE); while not Terminated do try case MsgWaitForMultipleObjects(1, FEvent, False, INFINITE, QS_ALLINPUT) of WAIT_OBJECT_0: begin if not ResetEvent() then // FEvent触发,须要作处理了。 // 请注意:FEvent通常由其它线程赋值或全局变量 // 且要注意: event建立时,是否手动管理类型的, // 若是是,则要ResetEvent,表示我收到此通知,我干活(注意: resetEvent返回True) end; WAIT_OBJECT_0 + 1: begin // 其它线程发送消息到本线程了,取出来,再根据消息不一样进行不一样处理。 while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do begin case msg.message of WM_MYMSG_0: ; // do my msg WM_MYMSG_1: ; // do my msg1 ... else DispatchMessage(msg); end end; end; end; except // todo: except end; end;
大概这些,不知想把要说的说完没。
水平有限,若有雷同,就是盗链,:D
2014.11.07 by qsl