周期性运行你应该在Execute中
while not Terminated do
begin
//此处加标志判断是否执行下面语句。
CallPlcMethodsHelper();
//如果周期性的执行,这边比如Sleep(1000);是最方便的。
end;你整个方法使用Synchronize,等于没有多线程,因为Synchronize是将方法同步到主线程执行,你应该在你需要操作VCL的地方使用Synchronize方法。临界区请uses SyncObjs;然后使用TCriticalSection类。
要用try...finally块保护起来,防止因为异常导致临界区未释放。
TCriticalSection.Enter();
try
//这里是业务逻辑
finally
TCriticalSection.Leave();
end;
如果业务逻辑代码可能会产生异常,请再使用try...except块保护,如果不保护,发生异常线程直接挂掉,你临界区自然不会Leave,导致死锁。
while not Terminated do
begin
//此处加标志判断是否执行下面语句。
CallPlcMethodsHelper();
//如果周期性的执行,这边比如Sleep(1000);是最方便的。
end;你整个方法使用Synchronize,等于没有多线程,因为Synchronize是将方法同步到主线程执行,你应该在你需要操作VCL的地方使用Synchronize方法。临界区请uses SyncObjs;然后使用TCriticalSection类。
要用try...finally块保护起来,防止因为异常导致临界区未释放。
TCriticalSection.Enter();
try
//这里是业务逻辑
finally
TCriticalSection.Leave();
end;
如果业务逻辑代码可能会产生异常,请再使用try...except块保护,如果不保护,发生异常线程直接挂掉,你临界区自然不会Leave,导致死锁。
2、如果你变量/对象是属于线程的尽量放入线程。
3、2个线程同时操作一块/一个对象时候使用临界区。
你的问题把你代码发出来看看就知道哪的问题了。
主程序EXE中打开一个DLL模块的Form,然后DLL的Form中声明了一个Private FIsDemoMode:boolean;(这里只列出最简单的例子,其实还有很多变量及TList之类的对象),然后在线程的Execute方法中访问FIsDebugMode,FrmEntry是和线程同一单元的Form实例,
try
if FrmEntry.FIsDebugMode then StrToInt('2');
//去掉了其他的业务逻辑
except
On E:Exception do FExcutionException:=E; //特别在线程里定义了个异常对象,然后在线程外处理该异常
end;
//线程外捕获异常
with FPlcDataReaderThread do
begin
if FExcutionException<>nil then Application.HandleException(FExcutionException);
end;这样的代码,我拉到一般的exe程序是可以执行的,不知道是不是在DLL里执行的原因。
FThreadCriticalSection.Enter();
try
try
if FrmEntry.FIsDebugMode then StrToInt('2');
except
On E:Exception do FExcutionException:=E;
end;
finally
FThreadCriticalSection.Leave();
end;假如是临界区操作问题,我觉得应该也只会导致TList的数据不正确,不至于报异常对吧,因为我只是修改TList中的值,没有其他操作。
begin
FThreadCriticalSection.Enter();
try
try
StrToInt('ABC'); //触发异常
except
On E:Exception do FExcutionException:=E;
end;
finally
FThreadCriticalSection.Leave();
end;
end;procedure TPlcDataReaderThread.Execute;
begin
while (not Terminated) do
begin
if FDoExecution then
begin
FLastExcutionTime:=now(); //发生异常后没有执行
FExcutionException:=nil;
//
CallPlcMethodsHelper(); FDoExecution:=false;
end;
end;
end; //以下代码每4秒执行一次
with FPlcDataReaderThread do
begin
if (not Terminated) then
begin
if FIsDebugMode then Log('FLastExcutionTime:'+DateTimeToStr(FLastExcutionTime));
if FExcutionException<>nil then Application.HandleException(FExcutionException);
FDoExecution:=true;
end; if Suspended or Terminated then Log('PLC reading thread stopped'); //发生异常后没有执行
end;
有异常时候的日志:
FLastExcutionTime SystemDate
2014/3/23 11:27:00 2014-03-23 11:27:12.687
2014/3/23 11:27:00 2014-03-23 11:27:08.620
2014/3/23 11:27:00 2014-03-23 11:27:04.557注释掉异常代码后的日志:
2014/3/23 11:09:57 2014-03-23 11:09:59.220
2014/3/23 11:09:53 2014-03-23 11:09:57.103
2014/3/23 11:09:48 2014-03-23 11:09:53.047从上面的结果我们看出异常是捕获到了,但是线程貌似就停掉了,但是线程的状态却没有变化,比如:Suspended和 Terminated属性都没有变化。