谁知道这个小小的多线程程序有什么问题?(200分)

  • 主题发起人 主题发起人 weiliu
  • 开始时间 开始时间
W

weiliu

Unregistered / Unconfirmed
GUEST, unregistred user!
以下是一个最简单的多线程小程序,要求是在命令行方式下运行,有FORM界面,运行几次后就会出现错误,大家看看是哪里的错?
程序如下:
unit temp_Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Label1: TLabel;
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
completed_status:boolean;
implementation

{$R *.dfm}

procedure Delay(msecs:integer);
var
FirstTickCount:dword;
begin
FirstTickCount:=GetTickCount;
repeat
Application.ProcessMessages;
until ((GetTickCount-FirstTickCount) >= dword(msecs));
end;

procedure count_num;
var
i:integer;

begin
i:=0;
while i<=2500000 do
begin
if completed_status=true then break;
i:=i+1;
form1.label1.Caption:=inttostr(i);
end;
end;

procedure TForm1.FormActivate(Sender: TObject);
var
DataThreadHandle:THandle;
ThreadID:DWORD;
begin
if uppercase(paramstr(1))='/R' then
begin
completed_status:=false;
DataThreadHandle:=CreateThread(nil,0,@count_num,nil,0,ThreadID);
if DataThreadHandle=0 then showmessage('Create Thread Failue !');
delay(5000);
completed_status:=true;
WaitForSingleObject(DataThreadHandle,INFINITE);
//TerminateThread(DataThreadHandle,0);
CloseHandle(DataThreadHandle);
end;
application.Terminate;
end;

end.
 
不知道怎么错的,试试这个,我改了下,主要不在线程代码中访问vcl label

unit unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

const WM_MyMsg=WM_User+8888;

type
TForm1 = class(TForm)
Label1: TLabel;
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure processWMMyMsg(var msg:TMessage); message WM_MyMsg;
end;

var
Form1: TForm1;
completed_status:boolean;

implementation

{$R *.dfm}

procedure Delay(msecs:integer);
var
FirstTickCount:dword;
begin
FirstTickCount:=GetTickCount;
repeat
Application.ProcessMessages;
until ((GetTickCount-FirstTickCount) >= dword(msecs));
end;

function count_num(P:pointer):Longint;stdcall; //procedure count_num; 根据楼下提示改了下,不影响结果
var
i:integer;
begin
i:=0;
while i<=2500000 do
begin
if completed_status=true then break;
i:=i+1;
SendMessage(Form1.Handle,WM_MyMsg,i,0)
end;
end;

procedure TForm1.FormActivate(Sender: TObject);
var
DataThreadHandle:THandle;
ThreadID:DWORD;
begin
if uppercase(paramstr(1))='/R' then
begin
completed_status:=false;
DataThreadHandle:=CreateThread(nil,0,@count_num,nil,0,ThreadID);
if DataThreadHandle=0 then showmessage('Create Thread Failue !');
delay(5000);
completed_status:=true;
WaitForSingleObject(DataThreadHandle,INFINITE);
//TerminateThread(DataThreadHandle,0);
CloseHandle(DataThreadHandle);
end;
application.Terminate;
end;

procedure TForm1.processWMMyMsg(var msg: TMessage);
begin
form1.label1.Caption:=inttostr(msg.WParam);
end;

end.
 
CreateThread要求的线程函数应该是procedure ThrdFun(v:Pointer)吧
 
to shangshang:
程序很怪,有时运行几十遍都不会有错,可某次却突然出现错误。
线程里有规定不能访问VCL控件吗?
 
线程里没有规定,不过vcl组件全部都是非线程安全的,比如可视组件的设备环境等,非常容易造成线程访问冲突,所以,你看任何一本线程书,都会说到,让你注意这一点。访问vcl组件时,尤其是可视组件时,切忌直接访问。
 
跟踪也发现不了错误的地方吗?这种臭虫最讨厌了
 
主要在于你的form1.label1.Caption:=inttostr(i);这行访问VCL组件。
VCL是非线程安全的,要把这个代码放在Synchronize里执行,
定义一个过程UpdateLabelCaption,然后通过Synchronize(UpdateLabelCaption)来操作VCL,
procedure UpdateLabelCaption
begin
form1.label1.Caption:=inttostr(i);
end;
 
其实也不是不可以访问VCL里的控件,可以用回调的方式间接访问。
还有,那个I,是一个临界变量,
i:=i+1;
你应该要这样写:InterlockedIncrement(I);
同样的道理,访问主线程的资源,最好是放到临界区去。
 
会不会由于我那个循环比较长,而我又用了程序运行5秒钟的方法来强行切断在线程里的循环,造成线程本身释放不干净呢?
 
跟踪也发现不了错误的地方吗?这种臭虫最讨厌了
 
后退
顶部