Как остановить фоновый поток, когда окно изображения закрыто в dm-скрипте - PullRequest
0 голосов
/ 24 июня 2018

Я пытаюсь написать 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 голосов
/ 24 июня 2018

А вот пример сценария, который использует закрытый окном слушатель для прерывания задачи.

Class CBackgroundWithListeners 
{
    Number isRunning
    Number imgID
    Image tmpIMG
    Number winListenID


    // Constructor and Destructor method for debugging reason
    // Always automatically called when object gets created or removed from memory
    CBackgroundWithListeners(object self) { 
        Result( "\n Creating object " + self.ScriptObjectGetClassName() )
        Result( " with ID: " + self.ScriptObjectGetID() )
    }
    ~CBackgroundWithListeners(object self) { 
        Result( "\n Destroying object " + self.ScriptObjectGetClassName() )
        Result( " with ID: " + self.ScriptObjectGetID() )
    }

    // Init Method
    Void Init( Object self, Number iID ){
        imgID = iID
        tmpIMG := GetImageFromID( imgID ) 
        If ( !tmpIMG.ImageIsValid() )
            Throw( "Image of ID " + imgID + " not found." )
        if ( 0 == tmpIMG.ImageCountImageDisplays() )
            Throw( "Image of ID " + imgID + " has no display." )

        DocumentWindow win = tmpIMG.ImageGetOrCreateImageDocument().ImageDocumentGetWindow()
        if ( !win.WindowIsValid() )
            Throw( "Image of ID " + imgID + " has no window." )

        winListenID = win.WindowAddWindowListener( self, "window_closed:HandleClosedAction;" ) 
    }
//
    Void StopRunning( Object self ){
        isRunning = 0
    }
//
    Number GetIsRunning( Object self ){
        return isRunning
    }
//    
    Void HandleClosedAction(object self, number e_fl, DocumentWindow Win)
    {
        self.StopRunning()
        win.WindowRemoveWindowListener( winListenID )
    }
//
    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(CBackgroundWithListeners)
    Image IMG := RealImage("test",4,64,64)
    IMG = random()
    IMG.ShowImage()
    IMG.SetWindowSize(512,512)
    cbkg.Init(IMG.GetImageID())
    cbkg.StartThread()
}
//
Main()
0 голосов
/ 24 июня 2018

Вы не можете остановить фоновый поток снаружи этого потока, то есть вы не можете прервать поток. Чтобы остановить фоновый поток, соответствующий код должен иметь условие остановки и выйти сам.

Чтобы управлять этим условием остановки из другого потока, вам нужно как-то "общаться" между двумя потоками. Это можно сделать разными способами. Самым простым является использование простой числовой переменной, которая проверяется фоновым рабочим кодом, но может быть установлена ​​с помощью любого другого «внешнего» кода. Пример этого можно найти в этом ответе здесь .

Вместо простой переменной можно также использовать какое-то общедоступное место, например, f.e. глобальные теги . Кроме того, некоторые более сложные объекты синхронизации потоков, такие как сигналы , мьютексы и семфоры , определены для языка сценариев и описаны в справочной документации здесь: 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 $$.
  • Инкапсулируйте как можно больше в класс
  • Добавить несколько проверок безопасности
  • Также добавьте обработчик событий закрытых окон , так что закрытие окна изображения также останавливает поток
  • Добавьте некоторый код отладки, чтобы показать, когда объект создается и когда он удаляется из памяти
  • У прослушивателя ключей есть возможность приостановить / отменить действие.
...