DigitalMicrograph下的线程大师 [英] Master of threads under DigitalMicrograph

查看:48
本文介绍了DigitalMicrograph下的线程大师的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在DigitalMicrograph中创建了两个线程,并且在脚本执行后立即执行它们.
我想要不同的东西.

I have created two threads in DigitalMicrograph and they are executed as soon as the script is executed.
I want something different.

让我们想象一下线程的两个按钮(启动和停止线程).
如何仅在按下按钮时添加代码以激活线程?

Let's imagine two buttons for the threads (start and stop thread).
How can I add code to activate the threads only when I push buttons ?

如果您有适合我的代码,这将非常有帮助.

It would be very helpful if you had a code exemple for me.

推荐答案

有几件事情要考虑:

  • 您不能在UIframe对象中分配新对象. (更确切地说,是通过UI动作调用的方法.您可以在构造函数中分配fe,也可以在开始时使用Init()方法.)因此,请事先分配它们,然后让UIframe对象知道它们.

  • You can not allocate new objects from within the UIframe object. (To be more precise: From a method invoked by a UI action. You can allocate f.e. in the constructor or with an Init() method at start.) Therefore you allocate them beforehand and then let the UIframe object know about them.

您通常希望UIframe对象了解线程对象,但也希望线程对象了解UIframe对象. (这样,如果线程对象中的某些对象希望UI可以更改.)

You often want the UIframe object to be aware of the thread object, but also the thread-object to be aware of the UIframe object. (So that the UI can change if something in the thread object wants it to.)

将对象作为对象的成员变量是有点危险的,因为这些对象只能在释放保持"对象后才能释放.如果两个对象彼此保持为成员变量,那么您将陷入僵局!因此,使用弱引用可以节省资源:仅保留 objectID 数字作为成员变量,并根据需要查找对象.

Having objects as member variables of objects is a bit dangerous, because those objects can only be released once the 'keeping' object gets released to. If two objects hold each-other as member variables, you're in a dead-locked situation! For this reason, it is save to use weak referencing: Keep only the objectID numbers as member variables and look objects up on need.

下面的代码示例应为您提供一个起点.它由2个班级和一个主要电话组成.在此答案中拆分代码,只需复制&将其粘贴到单个脚本文件中进行测试.

The following code-example should give you a starting point. It consists of 2 classes and a main call. The code is split in this answer, just copy & paste it into a single script file for testing.

第一个线程对象:

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( )
    }
  }
}

  • 任何线程类都是从 Thread 类派生的.

    • Any threading class is derived from the class Thread.

      该类具有两个成员变量.一个将保存UI对象的ID,另一个是一个简单的布尔值,以允许外部"调用来停止正在运行的线程.

      The class has two member variables. One will hold the ID of the UI-object, the other is a simple Boolean to allow 'outside' calls to stop a running thread.

      前两个方法是构造函数和析构函数.在此示例中并不需要它们,但是在脚本开发过程中将它们放入是一种很好的做法,因为它们将在结果窗口中指示何时创建该类的对象以及何时销毁该对象.这有助于跟踪内存泄漏和死锁情况.

      The first two methods are the constructor and the destructor. They are not really needed in this example, but it is good practice to put them in during script development, because they will indicate in the results-window when an object of that class gets created and when it gets destroyed. That helps tracking memory leaks and dead-lock situations.

      接下来的两个方法允许外部"调用来设置两个成员变量.

      The next two methods allow 'outside' calls to set the two member variables.

      RunThread 方法是任何 Thread 类的核心.它必须完全具有此签名,因为它会覆盖父类 Thread 的相应方法,我们从该方法派生我们的类 MyThread .当调用方法 StartThread()时, RunThread 方法将启动到单独的后台线程中. ( StartThread()是类 Thread 的方法.)

      The RunThread method is the heart of any Thread class. It has to be of exactly this signature because it overrides the according method of the parent class Thread from which we derive our class MyThread. The RunThread method gets launched into a separate background thread, when the method StartThread() is called. ( StartThread() is a method of the class Thread. )

      RunThread 中的实际代码分为两部分:

      The actual code in RunThread is in two parts:

      1. 一个动作循环",它可以做任何您想做的事情,但是如果布尔变量改变值,则允许快速退出.这是外部呼叫可以中断的方式.这将在后面进行讨论.

      1. An 'action-loop' doing anything you want but allowing a quick-exit if the Boolean variable changes value. This is how external calls can interrupt. This is discussed a bit further down.

      一个清理"部分,对象可以影响UI对象,下面还将进行讨论.

      A 'clean-up' part where the object can influence the UI object, discussed below as well.

    • 接下来是UI类:

      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()
        } 
      }
      

      • 任何对话框(UI)类都是从 UIframe 类派生的.

        • Any dialog (UI) class is derived from the class UIframe.

          该类只有一个成员变量:一个对象,它将是线程对象.

          This class has only one member variable: An object, which will be the thread-object.

          同样,有一个构造函数/析构函数方法可以简化调试.

          Again there are a constructor/destructor method for easier debugging.

          CreateDLG 方法构建描述对话框的tagGroup.我将不在这里详细介绍,但从本质上讲,它在显示时会创建以下对话框:

          The CreateDLG method builds the tagGroup describing the dialog. I will not go into details here, but essentially it creates the following dialog when displayed:

          Init()方法初始化该对象.基类 UIframe Init()方法需要一个描述性TagGroup,并返回UI对象本身.我们在扩展的 Init()方法的最后一行中调用此方法,并使用我们的类方法创建tagGroup:

          The Init() method initializes the object. The Init() method of the base class UIframe requires a descriptive TagGroup and returns the UI object itself. We call on this in the last line of our extended Init() method, and use our class-method to create the tagGroup:

          return self.super.init( self.CreateDLG() )

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

          The code before is what links our thread-object to the UI-object. We pass in a number, which is the object-ID of our thread-object. We now get the according object from memory and assign it to our local member variable. (NB: The variable now holds the object itself, not a copy or clone of it! )

          callThread = GetScriptObjectFromID( callThreadID )

          马上,我们检查查找是否成功并且实际上返回了一个有效的对象.如果没有,我们将使用抛出的异常来停止脚本.从现在开始,UI对象包含"线程对象并可以使用它.

          Right away, we check if the lookup was successful and actually returned a valid object. If not, we stop our script with a thrown exception. From now on, the UI-object 'contains' the thread-object and can use it.

          现在是反向链接.现在已经分配了UI对象,它也具有对象ID.我们将此数字输入到线程对象中.

          Now comes the back-link. Now that the UI object has been allocated, it also has an object-ID. We feed this number into our thread-object.

          callThread.SetLinkedDialogID( self.ScriptObjectGetID() )

          从现在开始,线程对象已很好地链接到UI对象.回顾 myThread 类,您会注意到我们使用相同的技巧来查找对象并将其本地存储在RunThread()方法中.

          From now on, the thread object is nicely linked to the UI-object. Looking back to the myThread class, you will notice that we use the same trick of looking up and locally storing the object in the RunThread() method.

          StartPressed()是链接到我们的对话框按钮的方法.此按钮是斜角按钮,因此我们查询其状态,即斜角按钮更改后的状态 并采取相应措施.我们要么将线程对象的RunThread()方法作为后台线程启动,要么调用相应的"interrupt"方法,该方法只是设置了布尔变量

          StartPressed() is the method linked to our dialog button. This button is a bevel button, so we query its state, which is the state after the bevel-button changed, and act accordingly. We either launch the RunThread() method of our thread object as a background-thread, or invoke the according 'interrupt' method, which simply sets the Boolean variable

          最后是主要脚本:

          void StartScript()
           {
             object threadObject = alloc( myThread )
             object dlgObject = alloc( myDialog ).Init( threadObject.ScriptObjectGetID() )
             dlgObject.display( "Dialog" )
           }
          StartScript()
          

          • 这里没有很多事情.我们首先创建myThread类的threadObject,然后创建对话框UI对象.

            • Not a lot going on here. We first create the threadObject of the myThread class, and then the dialog UI object.

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

              We initialize the dialog object with the ID of the existing threadObject, and then display it as a modeless dialog.

              需要注意的几点:

              • 每当在DigitalMicrograph脚本中使用对象变量时,都应将它们放入结构块中.这样可以确保在离开结构块时,对象不在范围之内并被删除.在主脚本中定义和分配的对象变量在脚本末尾不会被破坏.因此,我们将主脚本封装在方法本身中.

              • Whenever you use object variables in DigitalMicrograph scripting, you should put them into a structure block. This ensures that the objects get out-of-scope and deleted, when the structure block is left. Object variables defined and allocated in the main script are not destructed at the end of the script. For this reason, we have encapsulated the main script in a method itself.

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

              We have used two different methods of linking in this example:

              • 直接: myDialog 类实际上将线程对象本身保留为成员变量.尽管我们仅使用ID对其进行了初始化,但我们立即将对象链接到成员变量.

              • Direct: The myDialog class really keeps the thread-object itself as a member variable. Although we initialized it with the ID only, we immediately linked the object to a member variable.

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

              Weak reference: The myThread class only holds the object-ID of the dialog-object as a member variable.

              我们为什么要这样做?如果 myThread 类将对话框对象保留为成员,则这两个对象将在死锁情况下彼此保持对方.任何一个都不会因为另一个而被破坏.但是,为什么我们没有为 myDialog 类使用相同的控件呢?因为我们希望在后台线程本身中将对话框显示为无模式对话框

              Why have we done this? If the myThread class would keep the dialog-object as a member, then the two objects would hold each-other in a dead-lock situation. Neither can be destructed because of the other. But why have we not used the same for the myDialog class? Because we want to display the dialog as a modeless dialog in a background thread itself!

              想想主脚本:

              1. 我们创建线程对象
              2. 我们创建对话框对象
              3. 我们显示对话框对象(但是我们不会在这里停止脚本执行!)
              4. 脚本结束
              1. We create the thread-object
              2. We create the dialog-object
              3. We display the dialog-object (But we don't stop script execution here!)
              4. The script ends

              但是当脚本结束时,对象变量 threadObject dlgObject 超出范围!它们将立即被破坏,除非有某种记忆将它们保留在内存中. dlgObject 保留在内存中,因为我们将其显示为无模式对话框.当相应的对话框窗口关闭时,它将被释放.但是,什么使threadObject保持不变?没有!一旦 RunThread()方法完成,它将被释放并随后被销毁.但是,由于它是 dlgObject 的成员,因此不会被破坏.

              But when the script ends, the object variables threadObject and dlgObject go out of scope! They will be immediately destructed, unless something keeps them in memory. The dlgObject stays in memory, because we displayed it as modeless dialog. It will be released, when the according dialog window is closed. But what keeps the threadObject? Nothing! Once the RunThread() method has finished, it would be released and subsequently destructed. However, because it is a member of the dlgObject it will not be destructed.

              这篇关于DigitalMicrograph下的线程大师的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆