将处理状态的信息写入tcpserver.onexecute(..)函数内的GUI,我使用了以下命令序列
ExecuteDUMMYCommand(Global_Send_Record);
BitMap_PaintImageProcess;
TThread.Synchronize(nil, BitMap_PaintImageProcess);
代码在某些机器上运行良好,但在少数机器上运行失败。代码执行在atThhread.Synchronize命令处停止。我想在这些机器上,函数调用被困在死锁中 有机会找出背后的真正问题吗?
程序BitMap_PaintImageProcess,这里我创建了一个Bitmap并做了很多绘画工作,但似乎这段代码从未被执行过?
我尝试解释很长的代码并简化为要点,在处理Bitmapprocessingclass中的位图时隐藏了关键的线程问题。 在我的ServerMainForm的GUIProcessing过程中访问此类,该过程还具有INDY TCP Server组件。
{--------------- CLASS DEFINITION -----------------------------}
TBitMapProcessingClass = class()
FBitmap : TBitmap;
FList : TListOfSomething;
procedure ProcessTheBitmap(....);
......
(many many functions);
procedure Init;
procedure Free;
Procedure Create;
end;
TMainform = class(TForm)
MyServer : TIdTCPServer;
aBitMaoProcessingClass : TBitMaoProcessingClass;
procedure BitMap_PaintImageProcess;
procedure BitMap_ListProcess;
.....
end;
{------------------------- Implemantation ------------------------------}
procedure TMainform.IndyTCPServer.Onexecute()
begin
.......
ExecuteDUMMYCommand(Global_Send_Record);
BitMap_PaintImageProcess;
TThread.Synchronize(nil, BitMap_PaintImageProcess);
.......
end;
procedure TMainform.BitMap_PaintImageProcess;
begin
DoSomeServerVCLStuff(....);
aBitMapProcessingClass.ProcessTheBitmap;
DoSomeServerVCLStuff(....);
end;
答案 0 :(得分:0)
实际上我不知道BitMap_PaintImageProcess()做了什么,我有几个假设:
我建议使用MadExcept / Eurekalog。他们都有选项来检查主线程是否“冻结”。当发生这种情况时(在死锁期间),它们将显示当前的调用堆栈。拥有调用堆栈,您可以找出导致死锁的功能。
答案 1 :(得分:0)
关于发布的代码:
procedure TMainform.IndyTCPServer.Onexecute()
begin
.......
ExecuteDUMMYCommand(Global_Send_Record);
BitMap_PaintImageProcess; //-> You do VCL stuff in the context of Indy's thread!
TThread.Synchronize(nil, BitMap_PaintImageProcess);
end;
在BitMap_PaintImageProcess()
致电DoSomeServerVCLStuff(....)
。不要忘记Onyecute是从Indy的线程中为当前上下文触发的。即你从另一个非线程安全的线程(主线程中的其他线程)修改VCL。
关于你的评论:
...但是在这里我的复杂TBitmap处理类必须是整体活着的 我的服务器处于活动状态...
如果您只有一个(全局)实例进行图像处理,那么当您还在处理旧连接时,如果另一个客户端连接会发生什么(想想Parallel :))?应为每个新连接/上下文单独实例化图像处理类。对于GUI更新,您可以使用TIdNotify后代。
可能的解决方案:
type
{ tIdNotify Stuff }
TVclProc= procedure(imgClass: tMyImageProcessingClass) of object;
tIdNotifyDescendant = (tIdNotify)
protected
fImgClass: tMyImageProcessingClass;
fProc: TVclProc;
procedure DoNotify; override;
public
class procedure updateVcl(imgClass: tMyImageProcessingClass; vclProc: TVclProc);
end;
procedure tIdNotifyDescendant.DoNotify;
begin
inherited DoNotify;
FProc(fImgClass);
end;
class procedure tIdNotifyDescendant.updateVcl(imgClass: tMyImageProcessingClass; vclProc: TVclProc);
begin
with Create do
begin
fImgClass := imgClass;
fProc := vclProc;
Notify;
end;
end;
{ Indy stuff & other logic }
procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
begin
// Create your instance when the client connects
AContext.Data := tMyImageProcessingClass.Create;
end;
procedure TForm1.IdTCPServer1Disconnect(AContext: TIdContext);
begin
// Do cleanup
if assinged(AContext.Data) then
(AContext.Data as tMyImageProcessingClass).Free // Casting just for clarity
end;
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
imgProcClass: tMyImageProcessingClass;
begin
imgProcClass := acontext.Data as tMyImageProcessingClass;
// Do image processing
// Notify GUI for the progress:
tIdNotifyDescendant.updateVcl(AContext.data as tMyImageProcessingClass);
end;
提示:如果你进行JPEG处理并使用Draw()方法,请记住:TJPEGImage.Draw() is not thread safe
答案 2 :(得分:0)
我在BitmapProcessingclass上添加了一些细节以及现有类的线程安全扩展的想法...... 我需要在其他应用程序中使用现有的类...我需要在我的应用程序内部使用indy服务器进行扩展。 只有一个客户端我连接到一个服务器,或者他必须查询服务器的状态
type TBmpNotify = class(TIdNotify)
protected
FBMP: MyImageProcessingClass;
procedure DoNotify; override;
public
constructor Create(aBMP: MyImageProcessingClass);
function SetImageView(LL, UR: TPoint): Boolean;
procedure PaintBitMap;
function InitBitMap(x, y: Integer;
PixelFormat: TPixelFormat = pf24bit): Boolean;
destructor free;
end;
implementation
{ TBmpNotify }
constructor TBmpNotify.Create(aBMP: MyImageProcessingClass);
begin
// indise this class I also create
// class.TBitmap
// class.TList
// much more stuff ....
FBmp := MyImageProcessingClass.Create;
end;
procedure TBmpNotify.DoNotify;
begin
inherited;
end;
destructor TBmpNotify.free;
begin
FBmp.Free;
inherited;
end;
function TBmpNotify.InitBitMap(x, y: Integer;
PixelFormat: TPixelFormat): Boolean;
begin
// Write values to the List
// also modify TBitmap
// execution time of this function ~ 5 min
FBmp.InitBitMap(x,y,PixelFormat)
end;
procedure TBmpNotify.PaintBitMap;
begin
// much TBitmap, bitmap.canvas .... is used
// execution time of this function ~ 1 min
FBmp.PaintBitMap;
end;
function TBmpNotify.SetImageView(LL, UR: TPoint): Boolean;
begin
// this function takes about 1 min
FBmp.SetImageView(LL, UR);
end;
end.