关于多线程的结束问题,请大家发表一下自己的经验和看法,谢谢! ( 积分: 100 )

  • 主题发起人 主题发起人 cqwty
  • 开始时间 开始时间
C

cqwty

Unregistered / Unconfirmed
GUEST, unregistred user!
对于带定时器的线程(也就是间隔多少时间,做什么工作)的结束,在点击结束线程的按钮之后,总是需要等一个间隔时间左右,这时候,软件的界面处于死界面的状态,当然这种时间间隔的定时线程有很多实现方法,比如sleep,waitforsingleobject等。在陈宽达的深度历险中专门介绍一个章节的定时器使用。请教一下,如何快速结束这样的线程,而且保证资源得到释放。至于直接使用terminatethread这样的api就不用在此提出来了。因为释放不了资源,线程是结束了。
比如下面的代码:(只贴出execute部分)
1.使用sleep的;
var
precount,nextcount:dword;
begin
while not terminateddo
begin
preCount := GetTickCount();
Synchronize(sampledata);
nextCount := GetTickCount() - preCount;
if nextCount < FSampTime then
sleep(FSampTime - nextCount);
end;
end;
2.使用waitforsingleobject的;
var
timerid:integer;
htimerevent:Thandle;
begin
{ Place thread code here }
htimerevent := CreateEvent(nil, False, False, nil);
timerid := timesetevent(FSampTime,0,TFNTimecallback(htimerevent),0,time_periodic or time_callback_event_set);
while not terminateddo
begin
if waitforsingleobject(htimerevent,infinite) = wait_object_0 then
begin
sampledata;
end;
end;
timekillevent(timerid);
CloseHandle(htimerevent);
end;
请大家各抒己见吧。
 
对于带定时器的线程(也就是间隔多少时间,做什么工作)的结束,在点击结束线程的按钮之后,总是需要等一个间隔时间左右,这时候,软件的界面处于死界面的状态,当然这种时间间隔的定时线程有很多实现方法,比如sleep,waitforsingleobject等。在陈宽达的深度历险中专门介绍一个章节的定时器使用。请教一下,如何快速结束这样的线程,而且保证资源得到释放。至于直接使用terminatethread这样的api就不用在此提出来了。因为释放不了资源,线程是结束了。
比如下面的代码:(只贴出execute部分)
1.使用sleep的;
var
precount,nextcount:dword;
begin
while not terminateddo
begin
preCount := GetTickCount();
Synchronize(sampledata);
nextCount := GetTickCount() - preCount;
if nextCount < FSampTime then
sleep(FSampTime - nextCount);
end;
end;
2.使用waitforsingleobject的;
var
timerid:integer;
htimerevent:Thandle;
begin
{ Place thread code here }
htimerevent := CreateEvent(nil, False, False, nil);
timerid := timesetevent(FSampTime,0,TFNTimecallback(htimerevent),0,time_periodic or time_callback_event_set);
while not terminateddo
begin
if waitforsingleobject(htimerevent,infinite) = wait_object_0 then
begin
sampledata;
end;
end;
timekillevent(timerid);
CloseHandle(htimerevent);
end;
请大家各抒己见吧。
 
用sleep的我没话说,没办法,只能等
用timer的,可以把timerevent暴露出来,terminate,然后自己set一下timerevent,很快就结束了,或者重载terminat方法也行。
其实还有一种定时器的实现方法,就是waitsingleobject(hevent,sampletime)
如果超时返回,就触发一次,如果正常返回,就退出,原理和上面一样。
 
使用sleep的确实只能等待,没有办法了。对于后面一种,我想使用一个办法,那就是采用waitformultiobject这个函数来解决,这里面一个事件就是来源于主线程中(比如主窗体关闭)关闭消息,然后再在线程中用waitformultiobject函数来处理,跳出循环,不知道行不行!
 
怎么没有人来回答啊?我对我的程序做了如下的改变,可是出现运行的时候,cpu占用率非常高。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, SnmpDataSampUnit;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormClose(Sender: TObject;
var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
hExitEvent:THandle;
end;

var
Form1: TForm1;
snmpthread:snmpdatasamp;
implementation

{$R *.dfm}


procedure TForm1.Button1Click(Sender: TObject);
begin
if button1.Enabled then
begin
snmpthread:=snmpdatasamp.create('202.202.41.173','public',300,'SNMPv1','','');
button1.Enabled:=false;
button2.Enabled:=true;
end;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
button1.Enabled:=true;
button2.Enabled:=false;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
hExitEvent := CreateEvent(nil, False, False, nil);
setevent(hexitevent);
if button2.Enabled then
begin
snmpthread.Terminate;
snmpthread.Free;
button1.Enabled:=true;
button2.Enabled:=false;
end;
closehandle(hexitevent);
end;

procedure TForm1.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
button2.Click;
end;

end.
下面是多线程的execute的代码:
procedure SnmpDataSamp.Execute;
var
timerid:integer;
htimerevent:Thandle;
events:array[0..1] of thandle;
begin
htimerevent := CreateEvent(nil, False, False, nil);
timerid := timesetevent(5000,0,TFNTimecallback(htimerevent),0,time_periodic or time_callback_event_set);
events[0] := hExitEvent;
events[1] := htimerevent;
while not terminateddo
begin
case waitformultipleobjects(2,@events,false,infinite) of
wait_object_0:begin
break;
end;
wait_object_0+1:begin
sampledata;
end;
end;
end;
timekillevent(timerid);
CloseHandle(htimerevent);
end;
请大家帮忙诊断一下,谢谢,着急等待中~~~~~~~~~
 
不要再while terminated了,这个已经没有意义了
setevent以后,直接snmpthread.waitfor,就行了
或者waitforsingleobject(snmpthread.handle,infinite)
 
while not terminateddo
begin
case waitformultipleobjects(2,@events,false,infinite) of
wait_object_0:begin
break;
end;
wait_object_0+1:begin
sampledata;
end;
end;
end;
这部分代码改成什么?因为我采用定时器是为了间隔一定时间,让线程完成一定的工作,如果不用while not terminateddo
循环,那怎么处理
就直接下面的可以嘛?
 
while truedo
begin
case waitformultipleobjects(2,@events,false,infinite) of
wait_object_0:begin
break;
end;
wait_object_0+1:begin
sampledata;
end;
end;
end;
 
你的代码还有问题,线程创建时,hexitevent并没有创建啊,看代码你的线程应该是自动运行的,就是说在waitformultipleobject时,有一个event是没定义的
结束时setevent没作用
把createevent放到button1里面吧,要在snmpthread:=之前
setevent放到if里面,terminate就不要了,后面接着waitfor,然后free
 
我有一个event是在主窗体里面创建,但是当线程运行的时候,这个event没有创建,而是在主窗体的结束线程的这个按钮的onclick事件里面创建的。线程确实是一建立就运行的。我是想在主窗体中按下结束这个线程的按钮时,创建这个hexitevent事件,然后在线程中的waitformultipleobjects里面来等待这个事件,如果等到了,马上跳出循环,然后结束线程。不知道这样的想法是不是很天真,正在测试中!
 
events[0] := hExitEvent;
这一行有问题
除非你把他移到while的里面,每次循环都赋值,否则那个events[0]永远都是0
还是建议你先创建exitevent,在创建线程
 
有道理,先创建出来,然后只是在结束线程的按钮事件里面写setevent命令。可以试试这个想法。
 
还有问题么?没问题结贴、给分!
 
你这么着急干什么哦,还在测试问题还是有的。现在的问题是关于线程结束后,出现runtime error 216错误的问题了。这个问题我知道是什么原因,是结束线程的时候,
线程里面使用到的object和内存没有正确的释放造成的。我的线程里面,freeonterminate设置为true。然后结束线程的时候就直接调用thread的terminate。请问,怎么解决这个问题?
 
告诉过你不要调用terminate了,terminate只是把terminated私有变量设成true,别的什么也不干;
如果freeonterminate设置为true,那么你setevent以后,线程就会跳出while循环,很快结束,然后自动释放,那么你再调用terminate能不出错么--线程对象已经不存在了。
注意:
线程里面,while循环之后,要做好清场工作。
结束线程时,先setevent,然后snmpthread.waitfor,然后snmpthread:=nil;terminate和free都不要,就这些
 
谢谢,我马上测试,成功马上给分,放心,只是想多学点东西哈!
 
当结束线程的时候,加入下面两句,出现句柄无效的错误。我再查查资料看看。
 
问题搞定了,谢谢!在此说一下线程结束的时候要注意的东西,希望对以后遇到此问题的同仁有所帮助。对于在结束线程的过程中出现runtime error 216错误的情况,是因为内存没有释放好导致的。可能你的线程代码中在创建线程的时候有如下的语句
freeonterminate := true;
从delphi提供的帮助来看,在多线程中,如果这样设置的话,线程在结束的时候会安全的释放了你在线程中所创建的对象。但是事实并非如此,有时候是不会释放的,或者说释放不够彻底。那么怎么处理呢?其实问题并不难,通过对线程代码的分析可以发现,在多线程的里面,大部分都使用了如下的语句:(execute中)
while not terminateddo
begin
do
something;
end;
从这里可以找到突破点,那就是将你所创建的对象工作都在execute中来创建,然后在最后,也就是while not terminateddo
这个循环的后面做一项工作,那就是手动释放你所创建的对象。问题就可以圆满的解决了。
对于多线程里面使用到了定时器的问题,建议各位使用waitforsingleobject,或者waitformultileobjects,或者msgwaitformultileobjects来做,不要用sleep,因为精确度不够,当然,sleep也是可以解决问题的。只是在线程结束的时候,如果用了sleep,那就必须等带sleep完成才可以,所以很容易出现关闭应用程序的时候,因为要等待线程的结束,而主界面冻结的情况。
同时,waitfor……这一些函数,也有利于在处理一些多线程的同步上,比如说线程a结束才运行b,线程b结束,才运行c。对于主线程和从线程的通信,采用消息通知是最好的。当然要根据你的程序需要完成的功能来定。
最后谢谢帮助我的dfw。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
763
import
I
S
回复
0
查看
928
SUNSTONE的Delphi笔记
S
后退
顶部