gpt4 book ai didi

multithreading - DigitalMicrograph下的线程大师

转载 作者:行者123 更新时间:2023-12-03 13:00:14 25 4
gpt4 key购买 nike

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

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

如果您有适合我的代码示例,那将非常有帮助。

最佳答案

有几件事情要考虑:

  • 您不能从UIframe对象中分配新对象。 (更准确地说:是由UI Action 调用的方法。您可以在构造函数中分配f,例如,或者在开始时分配Init()方法。)因此,您需要事先分配它们,然后让UIframe对象知道它们。
  • 您通常希望UIframe对象了解线程对象,但也希望线程对象了解UIframe对象。 (因此,如果线程对象中的某些对象想要它,则UI可以更改。)
  • 将对象用作对象的成员变量有点危险,因为只有在释放“保持”对象后才能释放这些对象。如果两个对象彼此作为成员变量,那么您将陷入僵局!因此,使用弱引用是省力的:仅保留objectID号作为成员变量,并根据需要查找对象。

  • 以下代码示例应为您提供一个起点。它由2个类(class)和一个主要电话组成。在此答案中拆分了代码,只需将其复制并粘贴到单个脚本文件中以进行测试。

    首先是线程对象:
    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类派生的。
  • 该类具有两个成员变量。一个将保存UI对象的ID,另一个是一个简单的 bool 值,以允许“外部”调用停止正在运行的线程。
  • 前两个方法是构造函数和析构函数。在此示例中并不需要它们,但是在脚本开发过程中将它们放入是一种很好的做法,因为它们将在结果窗口中指示何时创建该类的对象以及何时销毁该对象。这有助于跟踪内存泄漏和死锁情况。
  • 接下来的两个方法允许“外部”调用来设置两个成员变量。
  • RunThread方法是任何Thread类的核心。它必须完全具有此签名,因为它会覆盖派生我们的类MyThread的父类Thread的相应方法。当调用方法StartThread()时,RunThread方法将启动到单独的后台线程中。 (StartThread()是Thread类的方法。)
  • RunThread中的实际代码分为两部分:
  • 一个“ Action 循环”,它可以做任何您想做的事情,但是如果 bool 变量改变值,则允许快速退出。这是外部调用可以中断的方式。这将在后面进行讨论。
  • 一个“清理”部分,对象可以影响UI对象,下面还将进行讨论。

  • 接下来是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类。
  • 此类只有一个成员变量:一个对象,它将是线程对象。
  • 再次提供了一个构造函数/析构函数方法,以简化调试过程。
  • CreateDLG方法构建描述对话框的tagGroup。我将不在这里详细介绍,但从本质上讲,它在显示时会创建以下对话框:

  • Init()方法初始化该对象。基类UIframe的Init()方法需要一个描述性TagGroup并返回UI对象本身。我们在扩展的Init()方法的最后一行中调用此方法,并使用我们的类方法创建tagGroup:
    return self.super.init( self.CreateDLG() )
    之前的代码将我们的线程对象链接到UI对象。我们传入一个数字,它是线程对象的对象ID。现在,我们从内存中获取相应的对象,并将其分配给我们的本地成员变量。 (注意:变量现在保存对象本身,而不是对象的副本或副本!)
    callThread = GetScriptObjectFromID( callThreadID )
    立即,我们检查查找是否成功,并且实际上返回了一个有效的对象。如果没有,我们将使用抛出的异常来停止脚本。从现在开始,UI对象“包含”线程对象并可以使用它。
  • 现在出现反向链接。现在已经分配了UI对象,它也具有对象ID。我们将此数字输入到线程对象中。
    callThread.SetLinkedDialogID( self.ScriptObjectGetID() )
    从现在开始,线程对象已很好地链接到UI对象。回顾myThread类,您将注意到我们使用相同的技巧来查找对象并将其本地存储在RunThread()方法中。
  • StartPressed()是链接到我们的对话框按钮的方法。此按钮是斜角按钮,因此我们查询其状态(斜角按钮更改后的状态),并采取相应的措施。我们要么将线程对象的RunThread()方法作为后台线程启动,要么调用相应的“interrupt”方法,该方法只需设置 bool 变量

  • 最后是主要脚本:
    void StartScript()
    {
    object threadObject = alloc( myThread )
    object dlgObject = alloc( myDialog ).Init( threadObject.ScriptObjectGetID() )
    dlgObject.display( "Dialog" )
    }
    StartScript()
  • 这里没有很多事情。我们首先创建myThread类的threadObject,然后创建对话框UI对象。
  • 我们使用现有threadObject的ID初始化对话框对象,然后将其显示为无模式对话框。

  • 需要注意的几点:
  • 每当在DigitalMicrograph脚本中使用对象变量时,都应将它们放入结构块中。这样可以确保在离开结构块时,对象不在范围之内并被删除。在主脚本中定义和分配的对象变量不会在脚本末尾销毁。因此,我们将主脚本封装在方法本身中。
  • 在此示例中,我们使用了两种不同的链接方法:
  • 直接:myDialog类实际上将线程对象本身保留为成员变量。尽管我们仅使用ID对其进行了初始化,但我们立即将对象链接到成员变量。
  • 弱引用:myThread类仅将对话框对象的对象ID作为成员变量保存。

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

    想想主脚本:
  • 我们创建线程对象
  • 我们创建对话框对象
  • 我们显示对话框对象(但我们不会在这里停止脚本执行!)
  • 脚本结束

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

    关于multithreading - DigitalMicrograph下的线程大师,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25500016/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com