代码如下
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更容易死锁。
没有评论:
发表评论