主线程中如何得知子线程已完成任务? ( 积分: 100 )

  • 主题发起人 主题发起人 bfox
  • 开始时间 开始时间
B

bfox

Unregistered / Unconfirmed
GUEST, unregistred user!
最近在做一个多串口通信的软件,多线程调用一个串口通信的COM组件.基本思路是:因为初始化串口需要较长时间,所以,首先动态的创建多个挂起的线程并保存在线程数组里.然后当有数据需要发送时,从线程数组中选择一个,设置需要传输的信息内容,然后RESUME线程,并将线程从数组里删除.当线程完成工作后,触发主线程的ThreadDone事件,然后主线程将其添加到数组中去.
可是在线程被RESUME后,总是不能触发ThreadDone事件,哪位高手做过类似的项目啊?请指教!
public
{ Public declarations }
comportcount:Integer;
ComPortDeviceArray:array of TNewComPortDevice;
procedure ThreadDone(Sender: TObject);

procedure Tfrm_main.btn_initClick(Sender: TObject);
var
i:integer;
ComPortDevice:TNewComPortDevice;
begin
btn_init.Enabled:=False;
comportcount:=StrToInt(edt_comportcount.Text);
setlength(ComPortDeviceArray,comportcount);
UseAblePortCount:=comportcount;
for i:= 0 to comportcount-1do
begin
ComPortDevice:=TNewComPortDevice.create(i+1);
ComPortDevice.OnTerminate:=ThreadDone;
ComPortDeviceArray:=ComPortDevice;
end;

btn_send.
Enabled:=True;
end;

procedure Tfrm_main.ThreadDone(Sender: TObject);
begin
 ....
btn_send.
Enabled:=True;
end;

procedure Tfrm_main.btn_sendClick(Sender: TObject);
begin
btn_send.
Enabled:=False;
 ...
 ComPortDevice.msg:='aabbccdd';
ComPortDevice.Resume;
end;

//这是线程的创建函数
constructor TNewComDevice.create(comport: Integer);
begin
Fcomport:=comport;
FreeOnTerminate := False;
inherited Create(true);
ComDevice := createoleobject('ComDevice.ComDevice1');
ComDevice.Connect(1, 19200);
end;
//这是线程的执行函数.用sleep (500)和ComDevice .SendMsg( Msg);都触发不了ThreadDone消息
procedure TNewsms.Execute;
var
i:Integer;
begin
sleep (500);
//ComDevice .SendMsg( Msg);

{ Place thread code here }
end;
 
最近在做一个多串口通信的软件,多线程调用一个串口通信的COM组件.基本思路是:因为初始化串口需要较长时间,所以,首先动态的创建多个挂起的线程并保存在线程数组里.然后当有数据需要发送时,从线程数组中选择一个,设置需要传输的信息内容,然后RESUME线程,并将线程从数组里删除.当线程完成工作后,触发主线程的ThreadDone事件,然后主线程将其添加到数组中去.
可是在线程被RESUME后,总是不能触发ThreadDone事件,哪位高手做过类似的项目啊?请指教!
public
{ Public declarations }
comportcount:Integer;
ComPortDeviceArray:array of TNewComPortDevice;
procedure ThreadDone(Sender: TObject);

procedure Tfrm_main.btn_initClick(Sender: TObject);
var
i:integer;
ComPortDevice:TNewComPortDevice;
begin
btn_init.Enabled:=False;
comportcount:=StrToInt(edt_comportcount.Text);
setlength(ComPortDeviceArray,comportcount);
UseAblePortCount:=comportcount;
for i:= 0 to comportcount-1do
begin
ComPortDevice:=TNewComPortDevice.create(i+1);
ComPortDevice.OnTerminate:=ThreadDone;
ComPortDeviceArray:=ComPortDevice;
end;

btn_send.
Enabled:=True;
end;

procedure Tfrm_main.ThreadDone(Sender: TObject);
begin
 ....
btn_send.
Enabled:=True;
end;

procedure Tfrm_main.btn_sendClick(Sender: TObject);
begin
btn_send.
Enabled:=False;
 ...
 ComPortDevice.msg:='aabbccdd';
ComPortDevice.Resume;
end;

//这是线程的创建函数
constructor TNewComDevice.create(comport: Integer);
begin
Fcomport:=comport;
FreeOnTerminate := False;
inherited Create(true);
ComDevice := createoleobject('ComDevice.ComDevice1');
ComDevice.Connect(1, 19200);
end;
//这是线程的执行函数.用sleep (500)和ComDevice .SendMsg( Msg);都触发不了ThreadDone消息
procedure TNewsms.Execute;
var
i:Integer;
begin
sleep (500);
//ComDevice .SendMsg( Msg);

{ Place thread code here }
end;
 
Thread.OnTerminate := OnUpdateTaskThreadDone;
结束后就会执行OnUpdateTaskThreadDone!
 
在完成任务之后,给指定的窗口发送消息
其实你的这种机制是一个线程池的概念.因此我建议
1.你能够参考完成一个通用线程池的管理类
2.对于线程池中的线程,是通用的,也就是说,不完成任何特定的工作,仅仅维护线程自身以及线程工作的状态
3.当需要线程完成特定工作时,传递一个特定的 函数指针/参数指针/状态回调 过去,通用线程类<1>设置自身为BUSY状态<2>以参数指针为参数调用函数指针<3>在调用返回之后,调用回调通知<4>设置自身状态为 NO_BUSY 状态
 
zjan521的应该是正解,在你的线程进入Execute方法后,就不必要让它离开(除非从线程池中移除销毁),通过配合如WaitForSingleObject等函数和状态的使用来调度线程。
 
SmallGhost,我知道可以这么写,可是我现在的问题是无法触发事件
特尔斐,zjan521,我现在的问题是不知道该如何确定线程当前的状态,你们觉得采用轮询的方式可以吗?
while msg <>
nulldo
begin
for i := 0 to comport count
begin
if comportarrar.suspond = true then

begin
comportarrar.sendmsg;
end;
end;
sleep(5000)
end;
这样行吗?
还是有其他更好的方法
 
[:D]收获很大
 
多人接受答案了。
 
后退
顶部