在DM脚本中关闭图像窗口时如何停止后台线程

时间:2018-06-24 04:01:48

标签: dm-script

我正在尝试编写一个包含后台线程的dm脚本,如以下示例代码所示。在此代码中,我想在关闭图像窗口时停止后台线程。我认为在这种情况下可能需要一些事件监听器。您能建议我如何通过关闭图像窗口事件来控制(即停止)后台线程吗?如果您可以建议对我的代码进行一些修改或显示您的示例代码,我将感谢您的合作。

// $BACKGROUND$
//
Class CBackground : Thread
{
    Number isRunning
    Number imgID
    Image tmpIMG
//
    Void Init( Object self, Number iID ){
        imgID = iID
        tmpIMG := GetImageFromID( imgID ) 
    }
//
    Void StopRunning( Object self ){
        isRunning = 0
    }
//
    Number GetIsRunning( Object self ){
        return isRunning
    }
//
    Void RunThread( Object self ){
        Result("Background thread is starting ......")
        isRunning = 1
        while (isRunning)
        {
            tmpIMG = random()
            sleep(0.5)
        }
        Result(" finished !!" + "\n")
    }
}
//
Void Main(){
    Object cbkg = alloc(CBackground)
    Image IMG := RealImage("test",4,64,64)
    IMG = random()
    IMG.ShowImage()
    IMG.SetWindowSize(512,512)
    cbkg.Init(IMG.GetImageID())
    cbkg.StartThread()
}
//
Main()

2 个答案:

答案 0 :(得分:1)

您不能从该线程之外停止后台线程,即您不能中断一个线程。为了停止后台线程,相应的代码需要具有停止条件并退出自身。

为了从另一个线程引导此停止条件,您需要以某种方式在两个线程之间“通信”。这可以通过许多不同的方式来完成。最简单的方法是使用一个简单的数字变量,该变量由后台运行代码检查,但可以通过任何其他“外部”代码进行设置。 An example for this can be found in this answer here

除了使用简单的变量,还可以使用一些常见的位置,例如f.e. 全局标签。另外,还为脚本语言定义了一些更复杂的线程同步对象,例如 signals mutexes semphores ,并在此处的帮助文档中进行了描述: Help on threading

如何外部线程可以将“中断”插入到后台运行线程中,这也可以通过许多不同的方式来完成。如上例所示,一种是通过一些打开的对话框进行用户交互。正如作者所提到的,另一种方法是具有一些事件侦听器代码来触发此事件。 以下示例在图像上附加了一个键侦听器,以便(此图像位于最前面并处于选中状态)用户可以按ESC按钮停止线程。

我正在使用提供的脚本进行最少的修改来显示此内容:

// $BACKGROUND$
//
Class CBackground : Thread
{
    Number isRunning
    Number imgID
    Number keyListenID
    Image tmpIMG
//
    Void Init( Object self, Number iID ){
        imgID = iID
        tmpIMG := GetImageFromID( imgID ) 
        ImageDisplay disp = tmpIMG.ImageGetImageDisplay(0)
        keyListenID = disp.ImageDisplayAddKeyHandler( self, "KeyListenAction" )
    }
//
    Void StopRunning( Object self ){
        isRunning = 0
    }
//
    Number GetIsRunning( Object self ){
        return isRunning
    }

    /////////////////////////////////////////////////////////////////////////////
    Number  KeyListenAction(Object self, ImageDisplay disp, Object keydesc ) 
    {
        number b_keyhandled = 0
        If ( keydesc.MatchesKeyDescriptor("esc") ) 
        {
            disp.ImageDisplayRemoveKeyHandler( keyListenID )
            self.StopRunning()
            Result( "\nSend stopping flag, unregister Key-Listeners" )
            b_keyhandled = 1
        }
        return b_keyhandled;
    }
//
    Void RunThread( Object self ){
        Result("Background thread is starting ......")
        isRunning = 1
        while (isRunning)
        {
            tmpIMG = random()
            sleep(0.5)
        }
        Result(" finished !!" + "\n")
    }
}
//
Void Main(){
    Object cbkg = alloc(CBackground)
    Image IMG := RealImage("test",4,64,64)
    IMG = random()
    IMG.ShowImage()
    IMG.SetWindowSize(512,512)
    cbkg.Init(IMG.GetImageID())
    cbkg.StartThread()
}
//
Main()

但是,有些事情我会有所不同:

  • 使用适当的命令而不是旧的'$$ BACKGROUND $$'方法启动后台线程。
  • 尽可能地将其封装到类中
  • 添加一些安全检查功能
  • 还添加一个 windowsclosed 事件监听器,以便关闭图像窗口也可以停止线程
  • 添加一些调试代码以显示何时创建对象以及何时将其从内存中删除
  • 让关键侦听器暂停/取消暂停操作。

答案 1 :(得分:1)

这是使用 window-closed 侦听器中止任务的脚本示例。

{
  "compilerOptions": {
    "outDir": "build/dist",
    "module": "esnext",
    "target": "es2018",
    "lib": ["esnext", "dom"],
    "sourceMap": true,
    "allowJs": true,
    "jsx": "react",
    "moduleResolution": "node",
    "rootDir": "src",
    "forceConsistentCasingInFileNames": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": false, //here
    "strictNullChecks": true,
    "suppressImplicitAnyIndexErrors": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  },
  "exclude": [
    "node_modules",
    "build",
    "scripts",
    "acceptance-tests",
    "webpack",
    "jest",
    "src/setupTests.ts"
  ]
}