解决kbmMW Scheduler在任务中停止任务遇到的问题

kbmMW提供了强大的Scheduler Framework,用来做调度任务的算法,在我看来,Scheduler发展了几个版本之后,截至到目前为止,更象是一个多线程框架,用来开发多线程算法。关于如何应用Scheduler,我翻译了作者写过的所有文章,可以去查看。今天要写的是实际项目中遇到的一个问题,如何用Scheduler来解决以及在解决过程中遇到的问题。

先看下需求:

有一个定位任务,在定位时,我显示一个等待界面,如果定位超时,则隐藏这个等待界面。下面是写的第一个版本的代码,建立一个每秒执行一次的调度任务,如果超时,则隐藏等待定位结果的界面,并停止调度任务。这里让调度任务与主线程同步执行:

procedure TCustomGridViewCameraDoc.InitSchedule;
begin
  Scheduler.Schedule(
    procedure(const AScheduledEvent:IkbmMWScheduledEvent)
    begin
              //隐藏等待定位界面
        ... AScheduledEvent.Terminate;
//停止任务(必须 .SyncQueued) end).EverySecond(1).Synchronized.NamedAs('se_job1') end;

上面的代码出问题了,当调用AScheduledEvent.Terminate,应用卡死

换一种写法,测试正常:

procedure TCustomGridViewCameraDoc.InitSchedule;
begin
  se_job1 := Scheduler.Schedule(
    procedure(const AScheduledEvent:IkbmMWScheduledEvent)
    begin
            ... 
            AScheduledEvent.Terminate;//正常!
    end).EverySecond(1)
        .SyncQueued//Synchronized换成SyncQueued
        .NamedAs('se_job1')
end;

或者这样写,也正常:

procedure TCustomGridViewCameraDoc.InitSchedule;
begin
  se_job1 := Scheduler.Schedule(
    procedure(const AScheduledEvent:IkbmMWScheduledEvent)
    begin
              TThread.Synchronize(nil,procedure
              begin
                      ....;
              end);//这样同步主线程执行逻辑
            AScheduledEvent.Terminate;
    end).EverySecond(1).NamedAs('se_job1')
end;

算不算是bug呢?我也说不清了。

进一步测试,又发现问题,当用下面代码重新激活这个调度事件(ScheduledEvent)发现无法激活,即调度任务不执行了。

Scheduler.Events.GetByName('se_job1').Activate;

通过把AScheduledEvent.Terminate替换成AScheduledEvent.Activate(False),问题得到解决。通过这个问题可以得出结论:当调用Terminate方法后,这个事件将无法重新Activate

下面是最后的版本

procedure TCustomGridViewCameraDoc.InitSchedule;
begin
  //避免重复建立调度事件
  if Scheduler.Events.GetByName('se_job1') <> nil  then exit;
  //建立一个调度事件,命名为se_job1
  Scheduler.Schedule(
                      procedure(const AScheduledEvent:IkbmMWScheduledEvent)
                      begin
                              AScheduledEvent.Activate(False);//必须 .SyncQueued
                      end)
           .EverySecond(1)
           .SyncQueued
           .NamedAs('se_job1')
end;
原文地址:https://www.cnblogs.com/kinglandsoft/p/12372855.html