注意,没有线程的对象实例(TThread),只有ID或Handle另问也是如果只有ID或Handle,是否可以判断这是应用程序的主线程还是子线程呢?分不够另开贴加分,谢谢。
解决方案 »
- ------------------制作安装程序出错<求助!>
- 怎么把一个窗口置于topmost?--------十分急,分全给了!!!
- 寻<<PC游戏编程--人机博弈>>的电子版或下载网址,马上结帐!最好有源码!
- 再发:求救,将程序从98迁移到xp下的打印问题,请救助。
- treeview的问题,请各位帮给以解决!
- 在学delphi,但发现需要更系统的学习windows,请推荐几本好书,最好有下载网址
- 如何将sqlserver显示在dbgrid的数据导入到Access问题
- 使用OBJ文件
- 如何当前判定TStringGrid中哪一格被选定?还有如何判定TTreeView中是否有节点被选中?
- 关于view |Type Library窗口的问题!
- FastReport安装 : FR本身提供的Recompile.exe只能编译一个版本。
- 不调CoUninitialize会否有问题?
begin
//TTestThread 不存在
end
else
begin
//TTestThread 存在
end;
procedure TForm1.RzButton1Click(Sender: TObject);
var
a: TMyThread;
begin
a := TMyThread.Create(False);
if WaitForSingleObject(a.Handle, 5000) = WAIT_TIMEOUT then
ShowMessage('time out')
else
ShowMessage('ok');
a.Free;
if WaitForSingleObject(a.Handle, 5000) = WAIT_TIMEOUT then
ShowMessage('time out')
else
ShowMessage('ok');
end;
showmessage('MainThread') ;
你这样写是错的.
第一:
WaitForSingleObjectt(a.Handle,5000) //不要把时间设置成这么大,一般100就足够了,主线程阻塞太久很可能出现不可预知的错误第二:
a.Free; 不应该这样结束线程,一旦线程处于阻塞状态,整个主线程都会卡死第三:
线程里面应该时刻检查是否Terminated,否则,是释放不了的.
例如
线程里:procedure TMyThread.Execute;
var
i:Integer ;
begin
while not Terminated do
begin
inc(i,1);
OutputDebugString(PChar(inttostr(i)));
Sleep(100);
end;
end;
假如改为procedure TMyThread.Execute;
var
i:Integer ;
begin
while true do
begin
inc(i,1);
OutputDebugString(PChar(inttostr(i)));
Sleep(100);
end;
end;这是释放不了的写程序,最好用标准的方法去写,上面的例子在2000/XP下线程有可能可以结束,但是在Vista下线程是不可能会结束的
最好改为
a := TMyThread.Create(True);
a.Resume;线程创建还是需要有一定时间的,假如客户机器不好或者系统资源紧张,
立刻用WaitForSingleObject去检测可能会出问题.(Handle不存在或者,刚好一个别的线程结束了这个新建立的线程的Handle和刚结束的线程Handle相同,而得到错误的结果)结束线程应该用
a.Terminate;
a.free;
a:=nil;这样才是完全的清理了a如果对线程的操作需要非常精细,建议你建立一个监视线程去对其他线程进行检测,检测结果通过消息或者事件进行处理和控制.线程不是那么简单的东西,Delphi的封装有比较大的局限性.还是多用API吧
2、我例子中的线程没挂起
2、不知道你是否明白Execute和Terminated的关系,Execute函数是ThreadProc的主体,在如果我不检查Terminated,线程只是把里面的代码执行一次就进入等待结束状态而已,和线程是否能释放完全没关系。要时刻检查Terminated是因为TThread.Terminate(包括Free的时候调用的Terminate)只是在线程里设置了Terminated这个标记,如果不检查,线程就会停死在那个While循环,出不了Execute这个过程里而已。相信下面代码可以解答你的疑问:function ThreadProc(Thread: TThread): Integer;
var
FreeThread: Boolean;
begin
{$IFDEF LINUX}
if Thread.FSuspended then sem_wait(Thread.FCreateSuspendedSem);
{$ENDIF}
try
if not Thread.Terminated then
try
Thread.Execute; <- 看这里
except
Thread.FFatalException := AcquireExceptionObject;
end;
finally
FreeThread := Thread.FFreeOnTerminate;
Result := Thread.FReturnValue;
Thread.DoTerminate;
Thread.FFinished := True;
SignalSyncEvent;
if FreeThread then Thread.Free;
{$IFDEF MSWINDOWS}
EndThread(Result);
{$ENDIF}
{$IFDEF LINUX}
// Directly call pthread_exit since EndThread will detach the thread causing
// the pthread_join in TThread.WaitFor to fail. Also, make sure the EndThreadProc
// is called just like EndThread would do. EndThreadProc should not return
// and call pthread_exit itself.
if Assigned(EndThreadProc) then
EndThreadProc(Result);
pthread_exit(Pointer(Result));
{$ENDIF}
end;
end;
constructor TThread.Create(CreateSuspended: Boolean);
{$IFDEF LINUX}
var
ErrCode: Integer;
{$ENDIF}
begin
inherited Create;
AddThread;
FSuspended := CreateSuspended;
FCreateSuspended := CreateSuspended;
{$IFDEF MSWINDOWS}
FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, FThreadID); <- 看这里
if FHandle = 0 then
raise EThread.CreateResFmt(@SThreadCreateError, [SysErrorMessage(GetLastError)]);
{$ENDIF}
{$IFDEF LINUX}
sem_init(FCreateSuspendedSem, False, 0);
ErrCode := BeginThread(nil, @ThreadProc, Pointer(Self), FThreadID);
if ErrCode <> 0 then
raise EThread.CreateResFmt(@SThreadCreateError, [SysErrorMessage(ErrCode)]);
{$ENDIF}
end;
begin
if (FThreadID <> 0) and not FFinished then
begin
Terminate;
if FCreateSuspended then
Resume;
WaitFor;
end;
{$IFDEF MSWINDOWS}
if FHandle <> 0 then CloseHandle(FHandle); <- 看这里
{$ENDIF}
{$IFDEF LINUX}
// This final check is to ensure that even if the thread was never waited on
// its resources will be freed.
if FThreadID <> 0 then pthread_detach(FThreadID);
sem_destroy(FCreateSuspendedSem);
{$ENDIF}
inherited Destroy;
FFatalException.Free;
RemoveThread;
end;
确实FreeAndNil(a)等价于a.free; a:=nil; 只是为了展示清楚写成这样,见笑了至于为什么
我也说过了,主线程阻塞,可能会出现不可知的情况.
至少在我测试的时候,在Vista/XP/2000下我的代码能够正常判断和工作我不知道对于"挂起"这个词我们的理解是否一致,我的理解线程处于Suspended状态下才能称为挂起
我的代码中让Execute过程处于死循环状态,在我看来这不是挂起,只是死循环而已.
在Execute过程中,线程外部调用Terminate,并不一定能有效终止线程.这是我的理解
这个我不太懂,请指教...
然后看返回值或者GetLastError看看是不是有问题