Synchronize的使用问题,在不同的计算机上使用效果不一样(Synchronize代码的详细分析,PostMessage不能通知到主线程,消息丢失) (

  • 主题发起人 yanghai0437
  • 开始时间
Y

yanghai0437

Unregistered / Unconfirmed
GUEST, unregistred user!
Synchronize的使用问题,在不同的计算机上使用效果不一样(Synchronize代码的详细分析,PostMessage不能通知到主线程,消息丢失) ( 积分: 200 )<br />Synchronize的使用问题,在不同的计算机上使用效果不一样.
在联想品牌计算机上运行正常,在一台兼容机上运行造成死锁,界面没有反映,
不知道原因。还有一个现象就是我在能够正常执行的计算机上编译后,将可执行程序复制到
兼容机上后也能够正常执行,只要在这台兼容机上编译后就不能正常执行。紧急求助。
我刚才已经仔细分析了Synchronize的运行方式。
第1步:线程调用Synchronize
第2步:Synchronize方法将方法添加到主线程的方法队列中
第3步:马上调用WakeMainThread方法,用PostMessage通知主线程检查同步方法
第4步:主线程收到消息后调用CheckSynchronize方法,执行需要执行的方法,然后产生
SetEvent(SyncProc.signal);
最后:线程收到SyncProc.signal事件信号后Synchronize方法完成。
我发现在这个过程中PostMessage不能通知到主线程,消息丢失,这样造成无法产生SyncProc.signal信号。
以下代码均为delphi6中的classes和Forms中的代码,省略部分代码
procedure TThread.Synchronize(Method: TThreadMethod);
....
if Assigned(WakeMainThread) then
WakeMainThread(Self);
{$IFDEF MSWINDOWS}
LeaveCriticalSection(ThreadLock);
try
WaitForSingleObject(SyncProc.Signal, INFINITE);//这里造成死锁
finally
EnterCriticalSection(ThreadLock);
end;
{$ENDIF}
.....
function CheckSynchronize: Boolean;
begin
...........
{$IFDEF MSWINDOWS}
SetEvent(SyncProc.signal);//在这里产生SyncProc.Signal
{$ENDIF}
..............
end;

procedure TApplication.WakeMainThread(Sender: TObject);
begin
PostMessage(Handle, WM_NULL, 0, 0);//Handle是正确的,但是不能收到这个消息。程序可以跟踪到这里,也就是说PostMessage消息丢失了
end;

procedure TApplication.WndProc(var Message: TMessage);//这个消息处理过程不能收到WakeMainThread发送的WM_NULL消息
begin
............
WM_NULL://这个消息调用下面的过程,再产生SyncProc.Signal,这样在TThread.Synchronize就不会死锁
CheckSynchronize;
//现在的问题是这个消息处理过程不能收到WakeMainThread发送的WM_NULL消息
............
end;
 
Synchronize的使用问题,在不同的计算机上使用效果不一样.
在联想品牌计算机上运行正常,在一台兼容机上运行造成死锁,界面没有反映,
不知道原因。还有一个现象就是我在能够正常执行的计算机上编译后,将可执行程序复制到
兼容机上后也能够正常执行,只要在这台兼容机上编译后就不能正常执行。紧急求助。
我刚才已经仔细分析了Synchronize的运行方式。
第1步:线程调用Synchronize
第2步:Synchronize方法将方法添加到主线程的方法队列中
第3步:马上调用WakeMainThread方法,用PostMessage通知主线程检查同步方法
第4步:主线程收到消息后调用CheckSynchronize方法,执行需要执行的方法,然后产生
SetEvent(SyncProc.signal);
最后:线程收到SyncProc.signal事件信号后Synchronize方法完成。
我发现在这个过程中PostMessage不能通知到主线程,消息丢失,这样造成无法产生SyncProc.signal信号。
以下代码均为delphi6中的classes和Forms中的代码,省略部分代码
procedure TThread.Synchronize(Method: TThreadMethod);
....
if Assigned(WakeMainThread) then
WakeMainThread(Self);
{$IFDEF MSWINDOWS}
LeaveCriticalSection(ThreadLock);
try
WaitForSingleObject(SyncProc.Signal, INFINITE);//这里造成死锁
finally
EnterCriticalSection(ThreadLock);
end;
{$ENDIF}
.....
function CheckSynchronize: Boolean;
begin
...........
{$IFDEF MSWINDOWS}
SetEvent(SyncProc.signal);//在这里产生SyncProc.Signal
{$ENDIF}
..............
end;

procedure TApplication.WakeMainThread(Sender: TObject);
begin
PostMessage(Handle, WM_NULL, 0, 0);//Handle是正确的,但是不能收到这个消息。程序可以跟踪到这里,也就是说PostMessage消息丢失了
end;

procedure TApplication.WndProc(var Message: TMessage);//这个消息处理过程不能收到WakeMainThread发送的WM_NULL消息
begin
............
WM_NULL://这个消息调用下面的过程,再产生SyncProc.Signal,这样在TThread.Synchronize就不会死锁
CheckSynchronize;
//现在的问题是这个消息处理过程不能收到WakeMainThread发送的WM_NULL消息
............
end;
 
贴出代码吧
 
//下面的代码都在线程中
//调用的地方
FSynchronizeIndex:=0;
Synchronize(Synchronizecedure);
...........................
procedure TStove.Synchronizecedure();
//同步事件方法
begin
if FSynchronizeIndex= 255 then
exit;//跟踪发现程序锁死时没有进入到这里
case FSynchronizeIndex of
0: IF Assigned (FOnTemperatureChanged) then
FOnTemperatureChanged(self);
1: IF Assigned (FOnAddHeatStatusChanged) then
FOnAddHeatStatusChanged(self);
2: IF Assigned ( FOnStoveException) then
begin

FOnStoveException(FStrException,0);
end;
end;
FSynchronizeIndex:= 255;
end;
 
所有的线程使用一个实例变量FSynchronizeIndex
这样你老人家认为安全吗?
还有你调用别的方法的时候 是不是也声明为STNC的
 
FSynchronizeIndex这个变量是这个线程类的私有变量,我认为应该没有问题
Synchronizecedure();
这个是线程类的私有过程
 
不是很会,抱歉
 
Synchronize是把代码同步到主线程中执行,这个就会造成界面没反应
所以要注意,线程执行体的代码中没有访问主线程中的vcl组件就不要Synchronize
 
to 迷糊,
Synchronize 方法中没有访问vcl组件的时候就会死锁吗?
FOnTemperatureChanged是我自定义的事件,在程序启动时确实没有关联到界面的事件。
 
如果没有访问界面的vcl组件就不要Synchronize
 
to 迷糊,
不是没有访问界面的vcl组件,只是在开始创建的时候没有访问而已。
如果没有访问界面的vcl组件而用了Synchronize就会造成死锁吗
 
不明白你所说的“死锁”是什么意思?如果是指“界面没有反映”的话,那么我告诉你
不管有没有访问界面的vcl组件,用Synchronize都会造成“界面没有反映”,因为那是在主线程中执行的
 
不是很了解,但是想问问:
两台机器的操作系统一样吗?
还有,能否再在第三部机器上试试?看看结果,也许可以找到原因不定。
线程觉得有时不是很好用,如果不能完全掌握使用方法,能否采用其他方式呢?
例如我觉得用Windows的消息触发我觉得是一个好的方法,我也有程序这样做,而且我觉得比较理想。
 
就是界面没有反应。
操作系统完全一样,都是win2000+SP2
procedure TThread.Synchronize(Method: TThreadMethod);
var
SyncProc: TSyncProc;
begin
if GetCurrentThreadID = MainThreadID then
Method
else
begin
{$IFDEF MSWINDOWS}
SyncProc.Signal := CreateEvent(nil, True, False, nil);
try
{$ENDIF}
{$IFDEF LINUX}
FillChar(SyncProc, SizeOf(SyncProc), 0);
// This also initializes the cond_var
{$ENDIF}
EnterCriticalSection(ThreadLock);
try
FSynchronizeException := nil;
FMethod := Method;
SyncProc.Thread := Self;
SyncList.Add(@SyncProc);
ProcPosted := True;
if Assigned(WakeMainThread) then
WakeMainThread(Self);
{$IFDEF MSWINDOWS}
LeaveCriticalSection(ThreadLock);
try
WaitForSingleObject(SyncProc.Signal, INFINITE);//我跟踪发现是这里死了,不知道SyncProc.Signal是由谁产生,WakeMainThread这个事件不知道怎样运行
finally
EnterCriticalSection(ThreadLock);
end;
{$ENDIF}
{$IFDEF LINUX}
pthread_cond_wait(SyncProc.Signal, ThreadLock);
{$ENDIF}
finally
LeaveCriticalSection(ThreadLock);
end;
{$IFDEF MSWINDOWS}
finally
CloseHandle(SyncProc.Signal);
end;
{$ENDIF}
if Assigned(FSynchronizeException) then
raise FSynchronizeException;
end;
end;
 
不会。。。。关注。。。。
不过一般都是因为操作系统才会出现这类情况,至于因为机器的原因造成这种不同。。。。难道和驱动有关系?
 
WaitForSingleObject(SyncProc.Signal, INFINITE)

晕,SyncProc.Signal可能在之前执行此函数之前在线程中已经被锁住了,然后这些代码是执行在主线程中,当然死锁了
这些代码也写得够差劲的,什么乱七八糟的
 
最好还是不用这种方式,界面的访问尽量用消息的方式(小数据量),代码再贴详细点,看看大家能不能帮你
 
to wbtvc
我贴的可是delphi6自带的代码。
 
可能是编译问题?有没有debug dcu选项?工程重新rebuild
 
所以说,会是不是你那部机器问题啊,都叫你试试其他机器啦。
 
顶部