打印本文 打印本文 关闭窗口 关闭窗口
Delphi中的线程类--之(4)
作者:武汉SEO闵涛  文章来源:敏韬网  点击数1863  更新时间:2009/4/23 18:35:44  文章录入:mintao  责任编辑:mintao
接下来就是最主要的部分了:调用WakeMainThread事件进行同步操作。WakeMainThread是一个TNotifyEvent类型的全局事件。这里之所以要用事件进行处理,是因为Synchronize方法本质上是通过消息,将需要同步的过程放到主线程中执行,如果在一些没有消息循环的应用中(如Console或DLL)是无法使用的,所以要使用这个事件进行处理。

而响应这个事件的是Application对象,下面两个方法分别用于设置和清空WakeMainThread事件的响应(来自Forms单元):

procedure TApplication.HookSynchronizeWakeup;

begin

  Classes.WakeMainThread := WakeMainThread;

end;

 

procedure TApplication.UnhookSynchronizeWakeup;

begin

  Classes.WakeMainThread := nil;

end;

上面两个方法分别是在TApplication类的构造函数和析构函数中被调用。

这就是在Application对象中WakeMainThread事件响应的代码,消息就是在这里被发出的,它利用了一个空消息来实现:

procedure TApplication.WakeMainThread(Sender: TObject);

begin

  PostMessage(Handle, WM_NULL, 0, 0);

end;

而这个消息的响应也是在Application对象中,见下面的代码(删除无关的部分):

procedure TApplication.WndProc(var Message: TMessage);

begin

  try

    with Message do

      case Msg of

        WM_NULL:

          CheckSynchronize;

  except

    HandleException(Self);

  end;

end;

其中的CheckSynchronize也是定义在Classes单元中的,由于它比较复杂,暂时不详细说明,只要知道它是具体处理Synchronize功能的部分就好,现在继续分析Synchronize的代码。

在执行完WakeMainThread事件后,就退出临界区,然后调用WaitForSingleObject开始等待在进入临界区前创建的那个Event。这个Event的功能是等待这个同步方法的执行结束,关于这点,在后面分析CheckSynchronize时会再说明。

注意在WaitForSingleObject之后又重新进入临界区,但没有做任何事就退出了,似乎没有意义,但这是必须的!

因为临界区的Enter和Leave必须严格的一一对应。那么是否可以改成这样呢:

        if Assigned(WakeMainThread) then

          WakeMainThread(SyncProc.SyncRec.FThread);

        WaitForSingleObject(SyncProc.Signal, INFINITE);

      finally

        LeaveCriticalSection(ThreadLock);

      end;

上面的代码和原来的代码最大的区别在于把WaitForSingleObject也纳入临界区的限制中了。看上去没什么影响,还使代码大大简化了,但真的可以吗?

事实上是不行!

因为我们知道,在Enter临界区后,如果别的线程要再进入,则会被挂起。而WaitFor方法则会挂起当前线程,直到等待别的线程SetEvent后才会被唤醒。如果改成上面那样的代码的话,如果那个SetEvent的线程也需要进入临界区的话,死锁(Deadlock)就发生了(关于死锁的理论,请自行参考操作系统原理方面的资料)。

死锁是线程同步中最需要注意的方面之一!

最后释放开始时创建的Event,如果被同步的方法返回异常的话,还会在这里再次抛出异常。

(待续)

上一页  [1] [2] [3] 

打印本文 打印本文 关闭窗口 关闭窗口