HELP!!!,终止单(多)个线程序死机(死锁)问题??? ( 积分: 100 )

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

cyradg

Unregistered / Unconfirmed
GUEST, unregistred user!
创建多个线程,用以下代码创建:
for i :=0 to thrdnum-1do
begin
g_Event :=CreateEvent(nil, True, False, nil);
//同步事件
FThreads :=CreateThread(nil,0,@Scan_ThreadProc,Pointer(i),0,tID);
end;

线程执行代码是:
function Scan_ThreadProc(lpParam:Pointer):DWORD;stdcall;
begin
while truedo
begin
//开始访问全局数据
EnterCriticalSection(g_CS);
//遇到这些标志就退出线程序
if (tcpscan.FTerminated) or (tcpscan.FsIPNum >=tcpscan.FIPScanNum) then
begin
SetEvent(g_Event[eventid]);//在此处设置段点根本就不会执行
LeaveCriticalSection(g_CS);
Result :=0;
exit;
end;
//结束访问全局数据
LeaveCriticalSection(g_CS);

..........//其他代码
//开始访问全局数据
EnterCriticalSection(g_CS);

.............//又访问全局变量

//结束访问全局数据
LeaveCriticalSection(g_CS);

.......//其他代码

//开始访问全局数据
EnterCriticalSection(g_CS);

.............//又访问全局变量

//结束访问全局数据
LeaveCriticalSection(g_CS);
end
以上是线程内部代码框架,如果不去主动想结束它,不论是运行1个线程还是运行多个线程,都不会出现问题并且都会主动结束
但是通过设置FTerminated变量来主动让线程结束就出现问题了,以下是结束线程代码片段:
//开始访问全局数据
EnterCriticalSection(g_CS);
//不加也没有用
FTerminated :=true;
//设置退出线程标志
//结束访问全局数据
LeaveCriticalSection(g_CS);
//不加也没有用
p :=@g_Event;
//事件数组
while n>0do
begin
if n>MAXIMUM_WAIT_OBJECTS then
_count :=MAXIMUM_WAIT_OBJECTS
else
_count :=n;
//在WaitForMultipleObjects处死掉了
wThrd :=WaitForMultipleObjects( _count , PWOHandleArray(p) , TRUE , INFINITE );
if wThrd<>WAIT_FAILED then
begin
for i :=0 to _count-1do
begin
CloseHandle(PWOHandleArray(p)^);
end;
end;
Dec(n,MAXIMUM_WAIT_OBJECTS);
p :=Ptr(Integer(p)+MAXIMUM_WAIT_OBJECTS*sizeof(THandle));
end;

当执行到WaitForMultipleObjects时候,挂了,事实1个线程也是这样,因为1个线程好调试,事实上,线程序内部的
那句SetEvent(g_Event[eventid])根本就不执行,好象哪里锁定了,请问问题出在哪里,谢谢.
 
发现执行只要执行这一句时,在状态条显示内容,必死:
//开始访问全局数据
EnterCriticalSection(g_CS);
//不执行以下语句就没问题
if Assigned(tcpscan.StatusBar) then
tcpscan.StatusBar.Panels[0].Text :=Format(
'扫描%d/%d',[tcpscan.FsIPNum,tcpscan.FIPScanNum]);
//结束访问全局数据
LeaveCriticalSection(g_CS);
顺便说一下,我是在主进程里设置FTerminated :=true来结束线程序的,那么如何解决,我要显示扫描结果。
 
现在发现只要线程访问主窗口的ListView和StatusBar对象时必死,不访问就没问题,可我要显示扫描数据呀,怎么办??
 
请问g_CS是在那里初始,又是在那里释放的?
 
你这个代码明显有问题,主线程里的VCL组件大部分都不是线程安全的,如果在子线程里调用VCL,那么必须通过Synchronize方法,这么改:
EnterCriticalSection(g_CS);
Synchronize(ShowProgress);
LeaveCriticalSection(g_CS);
proceure TYourThreadName.ShowProgress;
begin
if Assigned(tcpscan.StatusBar) then
tcpscan.StatusBar.Panels[0].Text :=Format(
'扫描%d/%d',[tcpscan.FsIPNum,tcpscan.FIPScanNum]);
end;

看来你需要多学学了,呵呵,给你个正常工作的Demo,参考一下:
定义个线程:
unit Unit2;
interface
uses
Windows, Classes, Messages, ComCtrls;
type
TTestThread = class(TThread)
private
Fpb: TProgressBar;
iPos: integer;
proceduredo
WhatVCLAction;
public
procedure Execute;
override;
constructor Create(pb: TProgressBar);
end;

implementation
{ TTestThread }
constructor TTestThread.Create(pb: TProgressBar);
begin
Fpb:= pb;
iPos:= pb.Position;
FreeOnTerminate:= true;
inherited Create(False);
end;

procedure TTestThread.DoWhatVCLAction;
begin
Fpb.Position:= iPos;
end;

procedure TTestThread.Execute;
begin
while iPos < 100do
begin
Inc(iPos);
//访问非线程安全的VCL组件的行为一定在 Synchronize 里!
synchronize(DoWhatVCLAction);
if Terminated then
exit;
Sleep(20);
end;
end;

end.
调用它:
procedure TForm1.Button1Click(Sender: TObject);
begin
TTestThread.Create(ProgressBar1);
end;
 
还有,别忘了初始化和删除临界区啊,用这个顺序调用:
InitializeCriticalSection(CS);
EnterCriticalSection(CS);
LeaveCriticalSection(CS);
DeleteCriticalSection(CS);
 
首先感谢各位,后面又改进代码了,代码改成以下方式没有出现问题:
1、线程内部代码:
EnterCriticalSection(g_CS);//开始锁
if ret =1 then
begin
if Assigned(tcpscan.FOnFind) then
tcpscan.OnFind(info.tgtIP,info.dport);
end;
LeaveCriticalSection(g_CS);//结束锁
2、主窗口代码:
procedure TMainForm.OnScanFind(ip: DWORD;
port: USHORT);
begin
FTCPScan.AddItem(ip,port);
// ListView1.Items.Count :=FTCPScan.Count;//仍然就是在这死
PostMessage(ListView1.Handle,LVM_SETITEMCOUNT,FTCPScan.Count,LVSICF_NOSCROLL);
end;
另外,man8888说的Synchronize方法是Thread对象的,我没有用Thread对象,是用FThreads :=CreateThread(nil,0,@Scan_ThreadProc,Pointer(i),0,tID);来创建的,所以不知道怎么用Synchronize,g_CS是全局变量,是在TCPSCAN对象的Create时InitializeCriticalSection(CS);
初始化,Destroy时DeleteCriticalSection(CS)销毁,可能象man8888说的那样,线程访问主进程的VCL时候,而同时主进程试图结束线程时,程序一定会挂(死锁),因为我没有用Thread对象,虽然PostMessage暂时解决问题,可总觉得这种方法蹩脚,有更好的方法吗?Synchronize也无法去试,应该可以吧
 
自己顶,有什么更好的方法吗?
 
多人接受答案了。
 

Similar threads

后退
顶部