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