本帖最后由 haochin 于 2010-09-20 09:00:51 编辑

解决方案 »

  1.   

    Terminate之后调用WaitFor来等待线程结束。
      

  2.   

    threada[i].Terminate;
    threada[i].WaitFor;
    threada[i].Free;
    threada[i] := nil;
      

  3.   

    你可以设定一个计数器, 初始值为运行的线程数目, 然后设定每个线程的OnTerminated 里写事件, 对这个变量进行减一. 当值为0的时候就代表所有的线程都完全停止了
      

  4.   

    waitfor 即可,也可以用WaitForMultipleObjects更稳妥些,WaitForMultipleObjects可以设置超时防止线程死锁造成程序崩了。
      

  5.   

    for i:= low(threada) to high(threada) do
    begin
      if assigned(threada[i]) then
      begin
        threada[i].Terminate;
        threada[i].WaitFor;
        FreeAndNil(threada[i]);
      end;
    end
      

  6.   

    主线程还真不能轻易waitfor,否则程序会停止响应(和死掉差不多)
    你可以再创建个线程,使用waitfor的方式等待所有的线程结束(结束的方式用你说的就可以,但是前提是你的线程函数中有对线程的 Terminated 变量进行判断才行)
    所有线程结束之后,你创建的这个线程采用通知的方式通知主线程(比如使用sendmessage或者线程同步函数)
      

  7.   

    以下是测试代码,采用的是
    用一个等待线程,使用WaitForMultipleObjects函数进行等待
    (程序中包括等待线程和测试线程)type
      TThreadArray = array of TThread;  TForm1 = class(TForm)
        btnThreadStop: TButton;
        btnThreadStart: TButton;
        procedure btnThreadStopClick(Sender: TObject);
        procedure btnThreadStartClick(Sender: TObject);
      private
        FThreads: TThreadArray;    procedure AllOver(Sender: TObject);
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}type
      TTestThread = class(TThread)
      protected
        procedure Execute; override;
      end;  TWaitThread = class(TThread)
      private
        FTA: TThreadArray;
        FOnAllOver: TNotifyEvent;
        procedure doAllOver();
      protected
        procedure Execute; override;
      public
        property OnAllOver: TNotifyEvent read FOnAllOver write FOnAllOver;
        property TA: TThreadArray read FTA write FTA;
      end;{ TTestThread }procedure TTestThread.Execute;
    begin
      while not Terminated do
        WaitForSingleObject(Self.Handle, 500);
    end;
    { TWaitThread }procedure TWaitThread.doAllOver;
    begin
      if Assigned(FOnAllOver) then FOnAllOver(Self);
    end;procedure TWaitThread.Execute;
    var
      I, N, K: Integer;
      hWait: array of  THandle;
    begin
      N := High(FTA) - Low(FTA) + 1;
      SetLength(hWait, N);
      for I := Low(FTA) to High(FTA) do
      begin
        hWait[I] := FTA[I].Handle;
        FTA[I].Terminate;    if Terminated then Exit;
      end;
      I := N div 64;
      K := N mod 64;
      while I > 0 do
      begin
        WaitForMultipleObjects(64, @hWait[(I - 1) * 64], True, INFINITE);
        Dec(I);    if Terminated then Exit;
      end;
      WaitForMultipleObjects(K, @hWait[I * 64], True, INFINITE);
      Synchronize(doAllOver);
    end;procedure TForm1.btnThreadStopClick(Sender: TObject);
    begin
      btnThreadStop.Enabled := False;
      with TWaitThread.Create(True) do
      begin
        FreeOnTerminate := True;
        OnAllOver := AllOver;
        TA := FThreads;
        Resume;
      end;
    end;procedure TForm1.AllOver(Sender: TObject);
    begin
      btnThreadStart.Enabled:= True;
    end;procedure TForm1.btnThreadStartClick(Sender: TObject);
    var
      I: Integer;
    begin
      btnThreadStart.Enabled:= False;
      SetLength(FThreads, 100);
      for I := 0 to 99 do
      begin
        FThreads[I] := TTestThread.Create(True);
        FThreads[I].FreeOnTerminate := True;
        FThreads[I].Resume;
      end;
      btnThreadStop.Enabled := True;
    end;
      

  8.   

    斜阳 (用户名:wxieyang) 高手不只是高手,还很热心两百分全结给你。。:)
    谢谢
    虽然我没有测试。但我知道一定行
      

  9.   

    我把结束那些线程的代码写到一个新的线程类里,可以吗?like this:
    procedure TWaitThread.Execute;
    begin
      FreeOnTerminate := True;             //我的作业线程里也加了这句,正常结束是会自自释放的吧
      FOR I := 1 TO 88 DO
      BEGIN
        if Main_F.threadA[I] <> nil then
        begin
          Main_F.threadA[I].Terminate;
          Main_F.threadA[I].WaitFor;
          Main_F.FreeAndNil(threadA[I]);      //这句要加吗  线程结束后,不是会自己释放吗?
        end;
      END;
    end;
      

  10.   

    procedure TWaitThread.Execute;
    begin
      FreeOnTerminate := True; //我的作业线程里也加了这句,正常结束是会自自释放的吧
      FOR I := 1 TO 88 DO
      BEGIN
      //下面的部分你是要访问主线程中的数据(Main_F.threadA),
      //你要保证你在这里操作这些数据的时候,主线程或者其他线程不会对Main_F.threadA进行些操作
      if Main_F.threadA[I] <> nil then
      begin
      Main_F.threadA[I].Terminate; //结束,这没问题,记得在被结束的线程中要有对Terminated变量的判断
      Main_F.threadA[I].WaitFor;   //在这里等待其实不是一个好的方式,原因下面会说  //下面这句加上就会出错,因为你在线程中已经指定线程结束就释放自己
      //Main_F.FreeAndNil(threadA[I]); //这句要加吗 线程结束后,不是会自己释放吗?
      end;
      END;
    end;好了,说说你上面的过程,首先,在线程的释放过程中,就包含Terminate和WaitFor,因此,如果你采用这种方式来结束你的线程,那么,直接在循环中写
    FOR I := 1 TO 88 DO
      FreeAndNil(Main_F.threadA[I])
    就可以,类的Free方法会主动判断被释放的类是否是nil,因此不用加入if Main_F.threadA[I] <> nil 的判断下面是线程类释放方法的一部分
    destructor TThread.Destroy;
    begin
      if (FThreadID <> 0) and not FFinished then
      begin
        Terminate;
        if FCreateSuspended then
          Resume;
        WaitFor;
      end;
      ......
    end;
    从中可以看到,其释放方式还是很不错了,其中考虑到了如果线程挂起,就先回复他,呵呵,至少你和我写的代码中就没有考虑到好了,再说说为什么直接WaitFor不好。因此一旦waitFor,当前线程就会停下来,直到等待结束才继续,而采用Terminate的方式结束线程,是需要在线程函数中配合的,需要不时地检查 Terminated 变量,换句和说,Terminate的方式不时立刻就能把线程结束,他需要等到下一个对Terminated的判断才能退出线程函数,也就是说要消耗一些时间。所以,我在上面才先把线程句柄得到,然后集中调用所有线程的Terminate方法,这样,这些被停止的线程就能并行地去结束(至少在多核心的机器上是并行的),然后在后面采用等待函数去等待。而你写的函数,是线性地一个一个结束。差别就在这里。呵呵