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, 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  

时间: 2024-10-16 21:57:55

delphi.thread.同步的相关文章

java线程研究---(8)Thread同步:锁的概念

(多线程数据共用的)示例代码: 先来看看"java线程研究---(7)Thread同步:多线程数据共用会产生问题"这篇文章里面主要的代码例子 ShareDataThread.java package thread; public class ShareDataThread implements Runnable { private int i = 0; @Override public void run() { while (i < 10) { i++; for (int j =

Delphi 线程同步技术(转)

上次跟大家分享了线程的标准代码,其实在线程的使用中最重要的是线程的同步问题,如果你在使用线程后,发现你的界面经常被卡死,或者无法显示出来,显示混乱,你的使用的变量值老是不按预想的变化,结果往往出乎意料,那么你很有可能是忽略了线程同步的问题. 当有多个线程的时候,经常需要去同步这些线程以访问同一个数据或资源.例如,假设有一个程序,其中一个线程用于把文件读到内存,而另一个线程用于统计文件中的字符数.当然,在把整个文件调入内存之前,统计它的计数是没有意义的.但是,由于每个操作都有自己的 线程,操作系统

delphi线程同步

本文完全摘自网络,仅供自己查询 上次跟大家分享了线程的标准代码,其实在线程的使用中最重要的是线程的同步问题,如果你在使用线程后,发现你的界面经常被卡死,或者无法显示出来,显示混乱,你的使用的变量值老是不按预想的变化,结果往往出乎意料,那么你很有可能是忽略了线程同步的问题. 当有多个线程的时候,经常需要去同步这些线程以访问同一个数据或资源.例如,假设有一个程序,其中一个线程用于把文件读到内存,而另一个线程用于统计文件中的字符数.当然,在把整个文件调入内存之前,统计它的计数是没有意义的.但是,由于每

Delphi thread exception mechanism

http://www.techques.com/question/1-3627743/Delphi-thread-exception-mechanism i have a dilema on how threads work in delphi, and why at a moment when a thread should raise an exception, the exception is not showed. bellow is the code with comments, ma

Java 多线程(Thread) 同步(synchronized) 以及 wait, notify 相关 [实例介绍]

场景描述 有一家很大的商场,在某市有几个商品配送中心,并有几家分店,这家商场经营很多的商品,平时运营情况是这样的: 根据各分店的商品销售情况,给分店配送相应需求量的商品:并上架到分店指让的位置,供客户选购. 客户选择自己需要的商品,然后到收银台交钱打包; 然后到一天的某个时候分店管理员(经理等),开始统计当前的销售情况,并计划向商品配送中心订购各商品的配送量: 场景模拟 1. 商场类; public class StoreMart { //商场这一天剩余的商品量 private static M

Thread 同步线程(打印机同步)

1.首先创建一个打印机对象 package cn.b.happy; public class Printer { Object o =new Object(); public void print(){ synchronized(o){ System.out.print("微"); System.out.print("冷"); System.out.print("的"); System.out.print("雨"); Syst

Thread同步机制比较

ThreadLocal和线程同步机制相比有什么优势呢?ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题. 在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量.这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大. 而ThreadLocal则从另一个角度来解决多线程的并发访问.ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离

Delphi线程同步的方法

更详细的可以参考:http://www.cnblogs.com/xumenger/p/4450659.html 或者参考之后的博客 四个系统内核对象(事件.互斥.信号.计时器)都是线程同步的手段,从这也能看出处理线程同步的复杂性:不过这还不是全部,Windows Vista开始增加了 Condition variables(条件变量).Slim Reader-Writer Locks(读写锁)等同步手段. 不过最简单.最轻便(速度最快)的同步手段还是 CriticalSection(临界区),但

delphi.thread.线程循环执行体结构

线程话题太大,又都是些坑,不知从哪方面讲起,所以,想一出是一出了. 不管怎样,我们从开始使用D,不管有没有用线程,其实它已经帮我们做了一个最完整的线程执行处理:Application.Run. 这行App.Run,在dpr,想来各位都经常能够看到,如果跟踪下去,我们就会发现,它其实就是一个最完整的线程执行体的结构了: 我将里面一些代码删除掉了,再将HandleMessage的代码复制过来,然后,代码如下: procedure TApplication.Run; var Msg: TMsg; be