这样会死锁,请解释原因。并使其不会死锁。(已经解决问题, 散分) (300分)

  • 主题发起人 主题发起人 wlmmlw
  • 开始时间 开始时间
简单的同步最好直接用TTHREAD.WAITFOR来做,这是TTHREAD内部实现的,比你的代码安全些,死锁原因我没测试你的代码不好下结论,不过我想也可能跟COM有关
 
你的代码确实死锁了
thrd := TOpenThread.Create(ClientDataSet1);
WaitForSingleObject(thrd.Handle, INFINITE);
Caption := 'Finish';
以上的代码很清楚,就是等子线程执行完了再更新 caption的值。
也就是说,在子线程未执行完的时候,无限期等待子线程的执行。


try
OleCheck(CoGetInterfaceAndReleaseStream(IStream(FStream), IID_IAppServer,
Appserver));
FNewData :=
AppServer.AS_GetRecords (FCDS.ProviderName,
-1,RecsOut,MetaDataOption,'',Params,OwnerData);
Synchronize(UpdateCDS);
finally
CoUninitialize;
end;

以上为子线程的代码,注意Synchronize(UpdateCDS);这一句,
这句话的意思是和主线程同步,也就是让主线程执行UpdateCDS函数,
可以这么理解,等待主线程空闲,主线程执行UpdateCDS,继续往下执行子线程其它代码。
楼主可以看到死锁的原因了吧。
WaitForSingleObject(thrd.Handle, INFINITE);

Synchronize(UpdateCDS);
这两句话导致了死锁。
主线程要等待子线程执行完成,而子线程却要等待主线程执行完成
互相等待,典型的死锁。
 
TClientDataSet和TDataSource;
不是可视化控件,应该是线程安全的,所以解决死锁的办法是直接调用
UpdateCDS;
而不是
Synchronize(UpdateCDS);
 
按照各位大侠这么说,换成以下就能过得去了?
可是仍然不行。
象yangying_2000说的,我也是觉得和COM有点关系。
procedure TOpenThread.Execute;
var
OwnerData: OleVariant;
RecsOut: Integer;
Params:OleVariant;
Appserver:IAppserver;
begin
OleCheck(CoInitialize(nil));
try
OleCheck(CoGetInterfaceAndReleaseStream(IStream(FStream), IID_IAppServer,
Appserver));
FNewData :=
AppServer.AS_GetRecords (FCDS.ProviderName,
-1,RecsOut,MetaDataOption,'',Params,OwnerData);
//Synchronize(UpdateCDS);
finally
CoUninitialize;
end;
end;
 
如果还是死锁,很容易按照死锁的原理往上推
FNewData :=
AppServer.AS_GetRecords (FCDS.ProviderName,
-1,RecsOut,MetaDataOption,'',Params,OwnerData);
这句代码是否要和主线程同步?!
CoUninitialize;
这句代码是否要和主线程同步?!
OleCheck(CoGetInterfaceAndReleaseStream(IStream(FStream), IID_IAppServer,
Appserver));
这句代码是否要和主线程同步?!
其实你这样很快就就能定位问题所在了。
给人与鱼,不如授人于渔,你自己查查吧。
 
大侠说得好。
上面的给你挑一个,怎么弄才通得过?
 
唉,你真是。
解决死锁问题,是要把锁打开,刚才的给你方法如果没有打开锁,你可以从另一方面下手。
也就是说,只要主线程和子线程有一边开锁就行。如果子线程开锁失败或者困难,就开主线程吧。
把主线程的以下一句
WaitForSingleObject(thrd.Handle, INFINITE);
改为

while truedo
begin
if WaitForSingleObject(thrd.Handle, 100) = WAIT_OBJECT_0 then
break;
end;
 
麻烦您啦,帮帮我。
可我还不知道它为什么会不行啊?
 
能不能解读一下以下的代码,从Classes里弄出来的。
class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord);
var
SyncProc: TSyncProc;
begin
if GetCurrentThreadID = MainThreadID then
ASyncRec.FMethod
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
if SyncList = nil then
SyncList := TList.Create;
SyncProc.SyncRec := ASyncRec;
SyncList.Add(@SyncProc);
SignalSyncEvent;
if Assigned(WakeMainThread) then
WakeMainThread(SyncProc.SyncRec.FThread);
{$IFDEF MSWINDOWS}
LeaveCriticalSection(ThreadLock);
try
WaitForSingleObject(SyncProc.Signal, INFINITE);
//这里不让过
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(ASyncRec.FSynchronizeException) then
raise ASyncRec.FSynchronizeException;
end;
end;
 
啊哈
少些了关键一句
while truedo
begin
if WaitForSingleObject(thrd.Handle, 100) = WAIT_OBJECT_0 then
break;
Application.ProccessMessage;
end;

 
没关系,先Look一Look我上面摘出来的代码。
 
现在行不行呀
 
上面的代码我其实跟你解释过了
可以这么理解,等待主线程空闲,等待主线程执行,然后继续往下执行子线程其它代码。
 
翻译成这样,你就好理解些,本质是一样
procedure TThread.Synchronize(Method: TThreadMethod);
begin
FSynchronizeException := nil;
FMethod := Method;
SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self));
if Assigned(FSynchronizeException) then
raise FSynchronizeException;
end;
 
哦,我得回去领会领会。谢谢大侠。
 
现在问题解决了吗?
 
[:D]还在调试...
 
//大侠们好,再look 一 look ,解释一下
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms,
Dialogs, StdCtrls, Comobj, ActiveX;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

TmR = record
v: integer;
end;

var
Form1: TForm1;
implementation
{$R *.dfm}
function threadfunc(P: Pointer): LongInt;
stdcall;
begin
Tmr(P).v := 10;
//mr.v := 10;
这一句和上面的那一句有什么区别?
//CoInitialize(nil);
//CoUnInitialize;
Result := 0;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
id: Cardinal;
thrd: THandle;
mr : TmR;
begin
mr.v := 1;
thrd := CreateThread(nil, 0, @threadfunc, Pointer(mr), 0, id);
waitforsingleobject(thrd, INFINITE);
Caption := format('%d', [mr.v]);
end;

end.
 
一个问题一个问题来,你这样让我们无法继续
 
这好象是同一个问题哦。
多线程,线程间的关系。
大侠辛苦了,有空就来坐坐,我去泡茶。
 
后退
顶部