以下程序运行时出错,出错描述如下:
主窗口有两个按钮,一个按钮创建线程,一个按钮调用Terminate使线程中止,调用后有个while语句判断主局变量是否为True,如果不是True,一直循环,当中止线程时,会出现进入progressAddOne函数,不会出来(可以从日志中显示出来),程序就一直在while中循环,也就是flag := True;这条语句没有执行到.
以下为主窗口
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, StdCtrls, Unit2;
type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
  testtheardtmp: testtheard;
  flag: Boolean;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
   testtheardtmp := testtheard.create;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
  testtheardtmp.Terminate;
  while not flag do
     sleep(10);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
   flag := False;
end;
end.//以下为线程单元
unit Unit2;
interface
uses
  Classes, Sysutils, FileCtrl, windows, progressfrm, extctrls, Controls;
type
  testtheard = class(TThread)
  private
     ffrmprogress: Tfrmprogress;
    { Private declarations }
  protected
    //进度条初始化
    procedure progressIni;
    //进度条加一
    procedure progressAddOne;
    procedure freeform;
    procedure Execute; override;
  public
    constructor Create;
  end;
implementation
uses
   Unit1;
{ testtheard }
constructor testtheard.Create;
begin
   ffrmprogress := Tfrmprogress.Create(nil);
   ffrmprogress.show;
   flag := False;
   FreeOnTerminate := False;
   inherited Create(False);
end;
procedure testtheard.Execute;
begin
   Synchronize(progressIni);
   while not Terminated do
   begin
      sleep(10);
      WriteLog('thread.txt', '进入<progressAddOne>');  //写日志
      Synchronize(progressAddOne);
      WriteLog('thread.txt', '出来<progressAddOne>');  //写日志
   end;
   WriteLog('thread.txt', '进入<freeform>');   //写日志
   freeform;
   WriteLog('thread.txt', '出来<freeform>'); //写日志
   flag := True;
end;
procedure testtheard.freeform;
begin
   ffrmprogress.free;
end;
procedure testtheard.progressAddOne;
begin
   ffrmprogress.ProgressBar1.Position := ffrmprogress.ProgressBar1.Position + 1;
end;
procedure testtheard.progressIni;
begin
   ffrmprogress.ProgressBar1.Max := 10000;
   ffrmprogress.ProgressBar1.Position := 0;
end;
end.//以下为进度条窗口
unit progressfrm;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Gauges, StdCtrls, ExtCtrls, ComCtrls;
type
  Tfrmprogress = class(TForm)                      
    Panel1: TPanel;
    ProgressBar1: TProgressBar;
  private
    { Private declarations }
  public
    { Public declarations }
  end;
implementation
{$R *.DFM}
end.

解决方案 »

  1.   

    线程的TERMINATE方法只能给TERMINATED属性赋值TRUE,不能真正中止线程.
    可以用API函数TERMINATETHREAD()强行中止线程,但这样线程所占用的资源不会得到释放,也不会关闭已经打开的文件.
      

  2.   

    我在VC6中写过多线程的程序,当时while (flag)的 flag 如果是在栈中(在类中,相当于在Form的class定义里面)的话就不稳定,好像根本无法判断flag的值,后来用信号量就没有这个问题。
      

  3.   

    我现在也用delphi写个多线程的东西,也是还没解决,楼主有什么心得拿出来交流交流吧
      

  4.   


    首先你释放窗体应该在线程Destroy 的时候释放
        destructor Destroy; override;
    destructor testtheard.Destroy;
    begin
       freeform;   WriteLog('thread.txt', '进入<freeform>');   //写日志
       WriteLog('thread.txt', '出来<freeform>'); //写日志
       flag := True;
      inherited;
    end;
    其次
    procedure TForm1.Button2Click(Sender: TObject);
    begin
      testtheardtmp.Terminate;
     //当你执行Terminate 的时候只是发送了一个命令, 线程有可以还在执行但还没有完成, 所以你下面可能会进行死循环
    while not flag do
         sleep(10);
    end;, 正确的写法应该是在Destroy的时个设置Flag destructor testtheard.Destroy;
    begin
       freeform;
      inherited;
    end;
      

  5.   

    你停止线程不应该用terminate方法,相反,你应该设置一个变量,然后在线程的循环中不断检查这个变量的值,如果需要退出,则跳出循环,线程就自动结束了。另外不知道你在执行了线程的Terminate方法之后为什么一直执行后面的那个循环。据我所知线程的terminate方法是调用后直接返回的,并不会等到线程完全结束了才返回的,从而导致了你的程序一直在执行terminate语句后的那个循环;而且你的循环时间间隔也比较短。建议你改一下,将while not terminated这句改为while not terminated and not flag do;然后你的button2不再调用线程的terminate方法,而是设置flag为true即可.
      

  6.   

    另外,在程序中建立的线程,最好不要直接操作VCL组件。因为VCL组件对线程的支持是有限的。比如你这个程序就在线程中创建一个进度条窗体,然后操作它。我认为这样做不好。此外你在写日志,也没有同步该操作,这样做也是很容易出错。
      

  7.   

    首先menliwxj(有缘)的说法不对, 我看上面的代码并没有操作公享单元的 VCL组件, 只有在操作共享资源的时候, 才是线程不安全, 而这个代码的 VCL组件是线程自己创建的所以不那个问题, 不过写日志确实应该写在Synchronize的操作里面