Multithreading 数码显微摄影下的线硕士

Multithreading 数码显微摄影下的线硕士,multithreading,dm-script,Multithreading,Dm Script,我在DigitalMicrograph中创建了两个线程,它们将在脚本执行后立即执行。 我想要一些不同的东西 让我们设想两个线程按钮(开始和停止线程)。 如何添加代码以仅在按下按钮时激活线程 如果您能为我提供一个代码示例,那将非常有帮助。有几件事需要考虑: 不能从UIframe对象中分配新对象。(更准确地说:通过UI操作调用的方法。您可以在构造函数中或在开始时使用Init()方法分配f.e。)因此,您可以预先分配它们,然后让UIframe对象知道它们 您通常希望UIframe对象了解线程对象,但

我在DigitalMicrograph中创建了两个线程,它们将在脚本执行后立即执行。
我想要一些不同的东西

让我们设想两个线程按钮(开始和停止线程)。
如何添加代码以仅在按下按钮时激活线程


如果您能为我提供一个代码示例,那将非常有帮助。

有几件事需要考虑:

  • 不能从UIframe对象中分配新对象。(更准确地说:通过UI操作调用的方法。您可以在构造函数中或在开始时使用Init()方法分配f.e。)因此,您可以预先分配它们,然后让UIframe对象知道它们

  • 您通常希望UIframe对象了解线程对象,但也希望thread对象了解UIframe对象。(这样,如果线程对象中的某些内容需要,UI可以更改。)

  • 将对象作为对象的成员变量有点危险,因为只有在将“keeping”对象释放到后才能释放这些对象。如果两个对象以成员变量的形式相互持有,则处于死锁状态!因此,使用弱引用是可取的:只保留objectID编号作为成员变量,并根据需要查找对象

下面的代码示例应该为您提供一个起点。它由2个类和一个主调用组成。代码在这个答案中被拆分,只需将其复制并粘贴到单个脚本文件中进行测试

首先是线程对象:

class myThread:Thread
{
  number linkedDLG_ID
  number externalBreak

  myThread( object self )  
  {
    result( self.ScriptObjectGetID() + " created.\n" )
  }

  ~myThread( object self )
  {
    result( self.ScriptObjectGetID() + " destroyed.\n" )
  }

  void SetLinkedDialogID( object self, number ID ) { linkedDLG_ID = ID; }
  void InterruptAtNextChance( object self ) { externalBreak = 1; }

  void RunThread( object self )
  {
    number maxLoop = 30

    object callDLG = GetScriptObjectFromID( linkedDLG_ID )
    externalBreak = 0
    for( number i=0; i<maxLoop; i++ )
    {
      sleep( 0.1 )
      Result( i + "\n" )
      if ( callDLG.ScriptObjectIsValid() )
      {
        callDLG.DLGSetProgress( "progress", (i+1)/maxLoop )
        callDLG.ValidateView()
      }

      if ( externalBreak )
        break;
    }

    // Cleanup at end of thread
    if ( callDLG.ScriptObjectIsValid() )
    {
      callDLG.DLGSetProgress( "progress", 0 )
      callDLG.LookUpElement( "DBevel" ).DLGValue( 0 )
      callDLG.ValidateView( )
    }
  }
}
class myDialog:UIframe
{
  object callThread

  myDialog( object self )
  {
    result( self.ScriptObjectGetID() + " created.\n" )
  }
  ~myDialog( object self )
  {
    result( self.ScriptObjectGetID() + " destroyed.\n")
  }


  TagGroup CreateDLG( object self )
  {
    image i := IntegerImage( "", 1, 0, 25, 25)
    i = 0; i[ 2 , 2 , 23 , 23 ] = 1;
    image onImage, offImage
    onImage   = RGB( 0*i , 200*i , 0*i )
    offImage  = RGB( 200*i , 0*i , 0*i )

    TagGroup tgItems, tg, button, label, progress
    tg = DLGCreateDialog("Dialog",tgItems)
    button = DLGCreateDualStateBevelButton( "DBevel", onImage, offImage, "StartPressed" )
    progress = DLGCreateProgressBar( "progress" ).DLGfill( "X" )
    label = DLGCreateLabel( "start/stop" )
    tgItems.DLGAddElement( DLGGroupItems( button , label ).DLGTableLayout( 2 , 1 , 0 ) )
    tgItems.DLGAddElement( progress )
    return tg
  }

  object Init(object self, number callThreadID )
  {
    // Assign thread-object via weak-reference
    callThread = GetScriptObjectFromID( callThreadID )      
    if ( !callThread.ScriptObjectIsvalid() )
      Throw( "Invalid thread object passed in! Object of given ID not found." )

    // Pass weak-reference to thread object
    callThread.SetLinkedDialogID( self.ScriptObjectGetID() )  
    return self.super.init( self.CreateDLG() )
  }

  void StartPressed( object self )
  {
    number active = self.LookupElement( "DBevel" ).DLGGetValue()
    if ( active )
      callThread.StartThread()
    else
      callThread.InterruptAtNextChance()
  } 
}
void StartScript()
 {
   object threadObject = alloc( myThread )
   object dlgObject = alloc( myDialog ).Init( threadObject.ScriptObjectGetID() )
   dlgObject.display( "Dialog" )
 }
StartScript()
  • 任何对话框(UI)类都是从UIframe类派生的

  • 这个类只有一个成员变量:一个对象,它将是thread对象

  • 同样,还有一个构造函数/析构函数方法,以便于调试

  • CreateDLG方法构建描述对话框的标记组。我将不在这里详细介绍,但它在显示时会创建以下对话框:

  • Init()方法初始化对象。基类UIframe的Init()方法需要一个描述性标记组,并返回UI对象本身。我们在extended Init()方法的最后一行调用它,并使用class方法创建标记组:

    返回self.super.init(self.CreateDLG())

    前面的代码将线程对象链接到UI对象。我们传入一个数字,它是线程对象的对象ID。现在,我们从内存中获取相应的对象,并将其分配给本地成员变量。(注意:变量现在保存对象本身,而不是对象的副本或克隆!)

    callThread=GetScriptObjectFromID(callThreadID)

    我们立即检查查找是否成功并实际返回了有效对象。如果没有,我们将使用抛出的异常停止脚本。从现在起,UI对象“包含”线程对象并可以使用它

  • 现在返回链接。既然已经分配了UI对象,它也有了一个object-ID。我们将这个数字输入到我们的thread对象中

    callThread.SetLinkedDialogID(self.ScriptObjectGetID())

    从现在起,thread对象将很好地链接到UI对象。回顾myThread类,您会注意到我们使用了相同的技巧,在
    RunThread()
    方法中查找并本地存储对象

  • StartPressed()是链接到对话框按钮的方法。这个按钮是一个斜面按钮,所以我们查询它的状态,即斜面按钮更改后的状态,并相应地进行操作。我们要么启动线程对象的RunThread()方法作为后台线程,要么调用相应的“interrupt”方法,该方法只设置布尔变量

最后是主脚本:

class myThread:Thread
{
  number linkedDLG_ID
  number externalBreak

  myThread( object self )  
  {
    result( self.ScriptObjectGetID() + " created.\n" )
  }

  ~myThread( object self )
  {
    result( self.ScriptObjectGetID() + " destroyed.\n" )
  }

  void SetLinkedDialogID( object self, number ID ) { linkedDLG_ID = ID; }
  void InterruptAtNextChance( object self ) { externalBreak = 1; }

  void RunThread( object self )
  {
    number maxLoop = 30

    object callDLG = GetScriptObjectFromID( linkedDLG_ID )
    externalBreak = 0
    for( number i=0; i<maxLoop; i++ )
    {
      sleep( 0.1 )
      Result( i + "\n" )
      if ( callDLG.ScriptObjectIsValid() )
      {
        callDLG.DLGSetProgress( "progress", (i+1)/maxLoop )
        callDLG.ValidateView()
      }

      if ( externalBreak )
        break;
    }

    // Cleanup at end of thread
    if ( callDLG.ScriptObjectIsValid() )
    {
      callDLG.DLGSetProgress( "progress", 0 )
      callDLG.LookUpElement( "DBevel" ).DLGValue( 0 )
      callDLG.ValidateView( )
    }
  }
}
class myDialog:UIframe
{
  object callThread

  myDialog( object self )
  {
    result( self.ScriptObjectGetID() + " created.\n" )
  }
  ~myDialog( object self )
  {
    result( self.ScriptObjectGetID() + " destroyed.\n")
  }


  TagGroup CreateDLG( object self )
  {
    image i := IntegerImage( "", 1, 0, 25, 25)
    i = 0; i[ 2 , 2 , 23 , 23 ] = 1;
    image onImage, offImage
    onImage   = RGB( 0*i , 200*i , 0*i )
    offImage  = RGB( 200*i , 0*i , 0*i )

    TagGroup tgItems, tg, button, label, progress
    tg = DLGCreateDialog("Dialog",tgItems)
    button = DLGCreateDualStateBevelButton( "DBevel", onImage, offImage, "StartPressed" )
    progress = DLGCreateProgressBar( "progress" ).DLGfill( "X" )
    label = DLGCreateLabel( "start/stop" )
    tgItems.DLGAddElement( DLGGroupItems( button , label ).DLGTableLayout( 2 , 1 , 0 ) )
    tgItems.DLGAddElement( progress )
    return tg
  }

  object Init(object self, number callThreadID )
  {
    // Assign thread-object via weak-reference
    callThread = GetScriptObjectFromID( callThreadID )      
    if ( !callThread.ScriptObjectIsvalid() )
      Throw( "Invalid thread object passed in! Object of given ID not found." )

    // Pass weak-reference to thread object
    callThread.SetLinkedDialogID( self.ScriptObjectGetID() )  
    return self.super.init( self.CreateDLG() )
  }

  void StartPressed( object self )
  {
    number active = self.LookupElement( "DBevel" ).DLGGetValue()
    if ( active )
      callThread.StartThread()
    else
      callThread.InterruptAtNextChance()
  } 
}
void StartScript()
 {
   object threadObject = alloc( myThread )
   object dlgObject = alloc( myDialog ).Init( threadObject.ScriptObjectGetID() )
   dlgObject.display( "Dialog" )
 }
StartScript()
  • 这里发生的事情不多。我们首先创建myThread类的Thread对象,然后创建dialog UI对象

  • 我们使用现有threadObject的ID初始化dialog对象,然后将其显示为无模式对话框

需要注意的几点:

class myThread:Thread
{
  number linkedDLG_ID
  number externalBreak

  myThread( object self )  
  {
    result( self.ScriptObjectGetID() + " created.\n" )
  }

  ~myThread( object self )
  {
    result( self.ScriptObjectGetID() + " destroyed.\n" )
  }

  void SetLinkedDialogID( object self, number ID ) { linkedDLG_ID = ID; }
  void InterruptAtNextChance( object self ) { externalBreak = 1; }

  void RunThread( object self )
  {
    number maxLoop = 30

    object callDLG = GetScriptObjectFromID( linkedDLG_ID )
    externalBreak = 0
    for( number i=0; i<maxLoop; i++ )
    {
      sleep( 0.1 )
      Result( i + "\n" )
      if ( callDLG.ScriptObjectIsValid() )
      {
        callDLG.DLGSetProgress( "progress", (i+1)/maxLoop )
        callDLG.ValidateView()
      }

      if ( externalBreak )
        break;
    }

    // Cleanup at end of thread
    if ( callDLG.ScriptObjectIsValid() )
    {
      callDLG.DLGSetProgress( "progress", 0 )
      callDLG.LookUpElement( "DBevel" ).DLGValue( 0 )
      callDLG.ValidateView( )
    }
  }
}
class myDialog:UIframe
{
  object callThread

  myDialog( object self )
  {
    result( self.ScriptObjectGetID() + " created.\n" )
  }
  ~myDialog( object self )
  {
    result( self.ScriptObjectGetID() + " destroyed.\n")
  }


  TagGroup CreateDLG( object self )
  {
    image i := IntegerImage( "", 1, 0, 25, 25)
    i = 0; i[ 2 , 2 , 23 , 23 ] = 1;
    image onImage, offImage
    onImage   = RGB( 0*i , 200*i , 0*i )
    offImage  = RGB( 200*i , 0*i , 0*i )

    TagGroup tgItems, tg, button, label, progress
    tg = DLGCreateDialog("Dialog",tgItems)
    button = DLGCreateDualStateBevelButton( "DBevel", onImage, offImage, "StartPressed" )
    progress = DLGCreateProgressBar( "progress" ).DLGfill( "X" )
    label = DLGCreateLabel( "start/stop" )
    tgItems.DLGAddElement( DLGGroupItems( button , label ).DLGTableLayout( 2 , 1 , 0 ) )
    tgItems.DLGAddElement( progress )
    return tg
  }

  object Init(object self, number callThreadID )
  {
    // Assign thread-object via weak-reference
    callThread = GetScriptObjectFromID( callThreadID )      
    if ( !callThread.ScriptObjectIsvalid() )
      Throw( "Invalid thread object passed in! Object of given ID not found." )

    // Pass weak-reference to thread object
    callThread.SetLinkedDialogID( self.ScriptObjectGetID() )  
    return self.super.init( self.CreateDLG() )
  }

  void StartPressed( object self )
  {
    number active = self.LookupElement( "DBevel" ).DLGGetValue()
    if ( active )
      callThread.StartThread()
    else
      callThread.InterruptAtNextChance()
  } 
}
void StartScript()
 {
   object threadObject = alloc( myThread )
   object dlgObject = alloc( myDialog ).Init( threadObject.ScriptObjectGetID() )
   dlgObject.display( "Dialog" )
 }
StartScript()
  • 无论何时在DigitalMicrograph脚本中使用对象变量,都应该将它们放入结构块中。这样可以确保在保留结构块时,对象超出范围并被删除。在主脚本中定义和分配的对象变量不会在脚本末尾被销毁。因此,我们将主脚本封装在方法本身中

  • 在本例中,我们使用了两种不同的链接方法:

    • Direct:myDialog类实际上将thread对象本身保留为成员变量。尽管我们仅使用ID初始化它,但我们立即将对象链接到一个成员变量

    • 弱引用:myThread类仅将对话框对象的对象ID作为成员变量保存

    我们为什么要这样做?如果myThread类将对话框对象保留为成员,那么这两个对象将在死锁的情况下相互保持。两者都不能因为另一个而被破坏。但是为什么我们没有在myDialog类中使用相同的方法呢?因为我们想在后台线程中将对话框显示为非模态对话框

    想想主脚本:

  • 我们创建线程对象
  • 我们创建对话框对象
  • 我们显示对话框对象(但我们不会在这里停止脚本执行!)
  • 脚本结束
  • 但是当脚本结束时,对象变量threadObject和dlgObject将超出范围!除非有什么东西把它们保存在内存中,否则它们会立即被销毁。dlgObject保留在内存中,因为我们将其显示为无模式对话框。当相应的对话框窗口关闭时,它将被释放。但是是什么让threadObjec