Delphi 定时器与线程间的问题

DoDoDTa 2013-03-01 01:52:59
最近遇到一个非常棘手的问题,复现频率及其的低.
形同运行环境描述:
只在客户端复现过(客户端XP或者2003),我本地是win7

问题描述:
在程序的主界面放了一个定时器控件,定时器Timer事件的逻辑如下,
tmrWork.Enabled := False;
tmrWork.Interval := 30 * 1000; //不在运行时间,半分钟检测一次
TSecThread.Create(StrList);

TSecThread类如下
TSecThread = class(TThread)
private
strList:TStrings;
ConText : TConText;
public
procedure Execute; override;
procedure SetstrList(var strL:TStrings);
constructor Create(var strL:TStrings);
end;
constructor TSecThread.Create(var strL: TStrings);
begin
SetstrList(strL);
StataCon := TConText.Create(strList) ;
FreeOnTerminate := True;
inherited Create(False);
end;

在线程TSecThread.Execute中处理逻辑如下,try finally部分做了业务处理,然后在finally end部分做了定时器的处理
inherited;
try
ConText.NowState.SetNextState();
Sleep(100);
ConText.NowState.SetNextState();
Sleep(100);
ConText.NowState.SetNextState();
finally
if Assigned(ConText) then
freeandnil(ConText);
FmMain.tmrWork.Enabled := True;
end;

问题出现了,安装上面的逻辑,只能有一个TSecThread线程在执行,可是有的时候会出现两个TSecThread在执行,请问有人出现过这样的问题没有?怎么解决?
...全文
820 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
subool 2013-03-25
  • 打赏
  • 举报
回复
定时器本身就是一个线程吧.
遥看雪景忆灵 2013-03-25
  • 打赏
  • 举报
回复
同意楼上定时器本身就是线程
DoDoDTa 2013-03-25
  • 打赏
  • 举报
回复
这个程序不是那么简单就能把定时器放到线程中的,因为还很多逻辑需求。 真不知道把分给谁,这个问题我自己似乎解决掉了,我模拟了一个信号,当线程创建时,信号+1,在执行线程的时候,如果信号>1则跳出,否则开始执行逻辑代码。 我这样更改,改动非常小。不知道以后还会不会出现这个问题,已经很长时间了,都没有再次出现这个问题。
UndefinedCoder 2013-03-06
  • 打赏
  • 举报
回复
inherited; try ConText.NowState.SetNextState(); Sleep(100); ConText.NowState.SetNextState(); Sleep(100); ConText.NowState.SetNextState(); finally if Assigned(ConText) then freeandnil(ConText); FmMain.tmrWork.Enabled := True; end; --------------------------------------------------------- FmMain.tmrWork.Enabled := True; 这句有问题。TTimer是独立于线程的对象。你这句应该用Synchronous执行。
yangtao6888 2013-03-05
  • 打赏
  • 举报
回复
不建议反复创建线程,如果TSecThread.create肯定是在你timer事件之外你还有执行过,我觉得TSecThread有两个的原因不在timer,而是在timer之外TSecThread.create被执行过两次。
yyfhz 2013-03-05
  • 打赏
  • 举报
回复
试着将恢复定时器的代码放到Thread的OnTerminate事件中
genispan 2013-03-04
  • 打赏
  • 举报
回复
1.线程里面写个死循环,每次延迟半分钟 不是一样的效果么? 2.可以定义一个全局变量 标识当前是否有前程在运行。
aawwmate 2013-03-04
  • 打赏
  • 举报
回复
没看明白咋回事
JohnYale 2013-03-02
  • 打赏
  • 举报
回复
在timer中用 WaitForSingleObject(handle, 0);试试看
haitao 2013-03-02
  • 打赏
  • 举报
回复
引用 11 楼 jinghai1776 的回复:
楼主不妨仔细思考下:你在线程里启动主线程定时器,又在定时器事件创建新线程,这就很可能两个线程同时存在,因为老线程释放需要一定时间。而且这种现象是随机的,因为这取决于操作系统如何分配 CPU 时间片。这种方案连想都不要想。
哦,原来已经贴了定时器的事件代码了,是先停止自己再启动线程 线程结束后再启动定时器,定时器30秒后才又先停止自己再启动线程 理论上,30秒的间隔是怎么都足够老线程释放的了 可能不释放,只是暂停和重启可能比较好 当然,本例直接在线程里暂停30秒更合理:简单且可靠
静_海 2013-03-01
  • 打赏
  • 举报
回复
楼主不妨仔细思考下:你在线程里启动主线程定时器,又在定时器事件创建新线程,这就很可能两个线程同时存在,因为老线程释放需要一定时间。而且这种现象是随机的,因为这取决于操作系统如何分配 CPU 时间片。这种方案连想都不要想。
haitao 2013-03-01
  • 打赏
  • 举报
回复
定时器事件怎么写的? 定时器事件的代码没贴,不知道里面怎么写,有没有先停止自己再启动线程? 如果的确是每次执行完停止30秒再重新执行,的确可以在线程里sleep
DoDoDTa 2013-03-01
  • 打赏
  • 举报
回复
To:sz_haitao 就是timer To: jinghai1776 这个办法比较好,不过看看还有其他的办法没有,改动有些大,这个是最后的选择了。
静_海 2013-03-01
  • 打赏
  • 举报
回复
没必要用定时器,也没必要反复创建和释放线程,直接在 Execute 中写一个循环: repeat // 这里是你的状态逻辑语句 Sleep(30000); // 等待半分钟重新开始 until Terminated; 这样就能不断循环处理,直到你把 Terminated 设成 True。为了能在终止时尽快反应,可以把 Sleep 缩短,用循环凑成半分钟,中间不断检测 Terminated 条件。
haitao 2013-03-01
  • 打赏
  • 举报
回复
定时器事件怎么写的? 另外,线程开始执行了,好像也没关定时器的动作?只有最后开定时器的代码
DoDoDTa 2013-03-01
  • 打赏
  • 举报
回复
时间精准不重要,我的目录是通过定时器控制线程的启动,定时器触发,把任务交给子线程处理,处理完,在将定时器激活,这样保证我的线程无限的循环运行,并且只有一个子线程在工作。 但是现在的问题就是,有的时候他会出现两个子线程同事在处理任务。
DoDoDTa 2013-03-01
  • 打赏
  • 举报
回复
To:andrew57 没明白是什么意思.
UnkownState 2013-03-01
  • 打赏
  • 举报
回复
定时器不会很精确,你比如在TSecThread.Create(StrList);先做判断, 定时器是主线程运行。
DoDoDTa 2013-03-01
  • 打赏
  • 举报
回复
我是要通过定时器来控制线程。
ok1411 2013-03-01
  • 打赏
  • 举报
回复

procedure TSecThread.Execute;  
var
  MsgRec: TMsg;
begin
  inherited; 
  FCheckTimer := TTimer.Create(nil);
  FCheckTimer.Interval := 30*1000;
  FCheckTimer.OnTimer := procTimer;
  FCheckTimer.Enabled := true;

  while GetMessage(MsgRec, 0, 0, 0) do
  begin
    TranslateMessage(MsgRec);
    DispatchMessage(MsgRec);
  end;        
  FCheckTimer.Enabled := False;
  FCheckTimer.free;
end;

procedure TSecThread.procTimer(Sender: TObject);
begin
  FCheckTimer.Enabled := False;
  try
    //do something
  finally
    FCheckTimer.Enabled := true;
  end;
end;
加载更多回复(1)

5,392

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧