2011年10月17日星期一

datasnap的初步 我用到的LogInfo函数

目前我的代码里面一直用到的LogInfo函数,其实很简单。就是服务器的Form里面放了一个TMemo,Memo里面记录下来消息,方面查看。
代码如下
TForm1 = class(TForm)
    Memo1: TMemo;
    procedure WM_Log(var msg: TMessage); message WM_LOG; 

procedure TForm1.WM_Log(var msg: TMessage);
var
  p: PChar;
begin
  p := PChar(msg.WParam);
  Form1.Memo1.Lines.Add(p);
  FreeMem(p, msg.LParam);
end;

function LogInfo(msg: string): Boolean;
var
  p: PChar;
  len: Integer;
begin
  //Form1.Memo1.Lines.Add(msg);
  len := Length(msg);
  GetMem(p, (len + 1) * SizeOf(Char));
  Move(msg[1], p^, len * SizeOf(Char));
  p[len] := #0; //for wm_log's freemem
  PostMessage(Form1.Handle, WM_LOG, WPARAM(p), (len + 1) * SizeOf(Char));
end;
前面我提到了,尽量不要在TIdThreadWithTask线程里去修改VCL的东西,如果要修改,也要通过发消息来修改,不要直接去修改,否则容易和主线程发生死锁。
 比如如果我的LogInfo函数直接写成
function LogInfo(msg: string): Boolean;
Form1.Memo1.Lines.Add(msg); 
end; 
会有什么问题呢,可以假想,点击Form1右上角的X关闭程序是,将关闭所有线程,线程关闭时如果我们有LogInfo(''),那么这个LogInfo就会直接操作主线程VCL,而主线程正等待其他线程的退出呢,从而可能死锁(因为VCL是以Windows消息来驱动的,主线程正等待所以消息处理不到)。

好,到这里,或许说加上TThread.Synchronize来搞就可以,其实也是不行的。TThread.Synchronize只是切题线程运行让TThreadMethod的内容给主线程执行罢了,以避免多线程的同步问题。上面的情况,主线程正等待子线程结束,子线程结束时说,我要切题到主线程记一下Log再退出,可主线程正等呢,切不过去,就死锁了,所以加上TThread.Synchronize更容易死锁。

没有评论:

发表评论