delphi.thread.同步
注意:此文只是讲线程间的同步,其它同步不涉及。
线程同步是个好话题,因为写线程经常会遇到,所以就写写自己知道的东西。
D里面,同步(特指线程同步)从线程的角度来分,有几种情况:
1:主线程与工作线程的同步
2:工作线程与主线程的同步
3:工作线程之间的同步。
同步,嗯,直白点讲,或可以说成是:A线程怎么通知B线程去做某某事,或者说某事需要:如何控制某一时间段内,A能做,B不能做(互斥)。
所以,手段很重要,也就有了API,也就有了方法:
1:lock(CriticalSection)
2:Event/Mutex/Semaphore + WaitFor
3:PostMessage/SendMessage/PostThreadMessage
简单的做一下介绍,可能不详细,具体请查看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, , , , PM_NOREMOVE);
while not Terminated do
try
// 从队列取消息
while PeekMessage(msg, , , , PM_REMOVE) do
begin
case msg.message of
WM_MYMSG_:
; // do my msg
WM_MYMSG_:
; // do my msg1
...
else
DispatchMessage(msg);
end
end; // 一般不建议使用WaitMessage,建议使用sleep()
// 因为退出时,你得发消息,否则Thread.Terminate()线程退不出来
Sleep(5);
except
// todo: except
end;
end;
示例代码B:
procedure TMyThreadB.Execute;
var
msg: TMsg;
begin
PeekMessage(msg, , , , PM_NOREMOVE);
while not Terminated do
try
case MsgWaitForMultipleObjects(, FEvent, False, INFINITE, QS_ALLINPUT) of
WAIT_OBJECT_:
begin
if not ResetEvent() then
// FEvent触发,需要做处理了。
// 请注意:FEvent一般由其它线程赋值或全局变量
// 且要注意: event创建时,是否手动管理类型的,
// 如果是,则要ResetEvent,表示我收到此通知,我干活(注意: resetEvent返回True)
end;
WAIT_OBJECT_ + :
begin
// 其它线程发送消息到本线程了,取出来,再根据消息不同进行不同处理。
while PeekMessage(msg, , , , PM_REMOVE) do
begin
case msg.message of
WM_MYMSG_:
; // do my msg
WM_MYMSG_:
; // do my msg1
...
else
DispatchMessage(msg);
end
end;
end;
end;
except
// todo: except
end;
end;
大概这些,不知想把要说的说完没。
水平有限,如有雷同,就是盗链,:D
2014.11.07 by qsl
delphi.thread.同步的更多相关文章
- Thread同步
今天本人给大家讲解一下多线程的线程同步,如有不对的或者讲的不好的可以多多提出,我会进行相应的更改,先提前感谢提出意见的各位了!!! 开始说线程同步前先来个小案例: 案例启:所有的类都在Demo01中, ...
- Delphi 线程同步技术(转)
上次跟大家分享了线程的标准代码,其实在线程的使用中最重要的是线程的同步问题,如果你在使用线程后,发现你的界面经常被卡死,或者无法显示出来,显示混乱,你的使用的变量值老是不按预想的变化,结果往往出乎意料 ...
- Delphi thread exception mechanism
http://www.techques.com/question/1-3627743/Delphi-thread-exception-mechanism i have a dilema on how ...
- Delphi线程同步
总结一下Windows常用的几种线程同步技术. 1.Critical Sections(临界段),源代码中如果有不能由两个或两个以上线程同时执行的部分,可以用临界段来使这部分的代码执行串行化.它只能在 ...
- Delphi Thread
Thread给几点说明:1.MyThread的实例作为TForm1的成员变量2.不要使用Form1这个全局变量,线程中可要使用它的Handle,你可以在Form中创建MyThread的实例时把Hand ...
- Delphi Thread.Queue与Synchronize的区别(差别: Synchronize是阻塞,Queue是非阻塞)
前话: 其实大家要学会看源码, 我接下来要说的这些东东,与其等别人讲,还不如自己搞几个代码试一下,印象还深刻点 TThread.Queue和TThread.Synchronize的区别, 效果上:二 ...
- Thread 同步线程(打印机同步)
1.首先创建一个打印机对象 package cn.b.happy; public class Printer { Object o =new Object(); public void print() ...
- Delphi线程同步(临界区、互斥、信号量)
当有多个线程的时候,经常需要去同步这些线程以访问同一个数据或资源. 例如,假设有一个程序,其中一个线程用于把文件读到内存,而另一个线程用于统计文件的字符数.当然,在整个文件调入内存之前,统计它的计数是 ...
- Delphi线程同步(临界区、互斥、信号量,包括详细代码)
当有多个线程的时候,经常需要去同步这些线程以访问同一个数据或资源. 例如,假设有一个程序,其中一个线程用于把文件读到内存,而另一个线程用于统计文件的字符数.当然,在整个文件调入内存之前,统计它的计数是 ...
随机推荐
- 暑假前的flag
暑假到了,为了简便新开了一个博客,供暑假刷体放一些题解,玩acm1年多了,cf还是蓝名,真是菜的一笔,明年就大三了,马上就要毕业了,然而还是啥也不会,兼职和智障没什么两样,当初大一吹的牛逼说要成为学校 ...
- ZipArchive之C++编译和调用
由于要用到zip的解压,就上网下载了CZipArchive类的源码(还是2000年的),里面有个示例,稍微修改下,就能正常运行. 就高兴地把lib拿出来,放到项目中了.捣鼓了快一个下午了,死活编译不通 ...
- Docker搭建Java Web运行环境
1. 前提条件 安装了Docker的64位Linux 操作系统 Linux操作系统镜像 Linux版本的JDK压缩包 Linux版本的Tomcat压缩包 2. 启动容器 容器是在镜像的基础上来运行的, ...
- TimeStamp
private void Form1_Load(object sender, EventArgs e) { textBox1.Text= GenerateTimeStamp(System.DateTi ...
- java分页问题
问题一:所有数据分页显示后 点击下一页跳转到第二页后 填写查询条件在点击查询按钮,分页出现问题(页码有问题) 默认没有从第一页开始显示 解决方案:问题出在取的当前页有问题,把当前页设置为第一页(0), ...
- OpenCV MAT基本图像容器
参考博客: OpenCv中cv::Mat和IplImage,CvMat之间的转换 Mat - 基本图像容器 Mat类型较CvMat和IplImage有更强的矩阵运算能力,支持常见的矩阵运算(参照Mat ...
- maven 私服搭建
1,下载 https://sonatype-download.global.ssl.fastly.net/nexus/oss/nexus-2.14.2-01-bundle.zip 2,解压 3,安装 ...
- 原创跑酷小游戏《Cube Duck Run》 - - 方块鸭快跑
自从unity5出来才开始关注unity,业余时间尝试做了个小游戏: <方块鸭快跑> (Cube Duck Run) 像素风,3d视角,色彩明快,有无尽和关卡两种模式. 应用连接: goo ...
- 自动运维:Ansible -ansible tower
文档主页:http://docs.ansible.com/参考文档:http://docs.ansible.com/ansible/参考文档:http://docs.ansible.com/ansib ...
- Mysql 安装-操作-备份
Mysql 5.7 安装windows 1.配置mysql的path->系统属性->环境变量-path添加最后 2.配置目录和主从 [mysqld]port = 3306 basedir= ...