简体   繁体   English

C#中的线程+ TabControl

[英]Threading + TabControl in C#

This is a slightly weird setup, and I'm planning on redoing it, but, if nothing else, I'm hoping that I can learn a lot more about threading as a result of this. 这是一个有点奇怪的设置,我正在计划重做它,但是,如果没有别的,我希望我可以学习更多关于线程的结果。

At the moment, I've got an application I'm building which uses a TabControl Windows Form as the basis for its design. 目前,我有一个我正在构建的应用程序,它使用TabControl Windows窗体作为其设计的基础。 I've got a number of different things I need to do, so I figured this might be the best way to do it. 我有很多不同的事情需要做,所以我认为这可能是最好的方法。

Now, I'm coding in a Macro function into the program, such that a user can record and playback mouse and keyboard actions. 现在,我正在将Macro函数编码到程序中,以便用户可以记录和回放鼠标和键盘操作。 That has been perfectly fine, and mixing it with System.Timers.Timer has been ok as well. 这非常好,并将它与System.Timers.Timer混合也一直没问题。 However, the DLL I'm using uses Thread.Sleep(x) to pause the thread in between keystroke and mouse executions. 但是,我正在使用的DLL使用Thread.Sleep(x)在击键和鼠标执行之间暂停线程。

At this point, the button is on a different tabpage and switches to a different page. 此时,该按钮位于不同的标签页上,并切换到其他页面。 However, the point blank setup resulted in the program hanging while waiting for the macro execution to complete. 但是,空白点设置导致程序在等待宏执行完成时挂起。

To explain a little better: 为了更好地解释一下:

  • User clicks button in main tabcontrol. 用户单击主tabcontrol中的按钮。
  • Tabcontrol.SelectedIndex is switched to the proper page, but does not refresh page (I tried calling this.Refresh(), it didn't work) Tabcontrol.SelectedIndex切换到正确的页面,但不刷新页面(我试着调用this.Refresh(),它没有工作)
  • Macro executes 宏执行
  • Tabcontrol finishes loading the page, but by this point, the necessary macro has already executed and the loaded page is superfluous. Tabcontrol完成加载页面,但到此时,必要的宏已经执行,加载的页面是多余的。

To get around this, I started researching threading and seeing how I could use that. 为了解决这个问题,我开始研究线程并了解如何使用它。 I came up with the following code inside a class: 我在一个类中提出了以下代码:

Class X{
  Thread othread;
  ...        
  public void Play()
  {
    if ((othread != null) && !(othread.IsAlive))
    {
        othread = new Thread(playValues);
        GC.Collect();
    }
    else if (othread == null) othread = new Thread(playValues);
    else return;
    othread.Start();
  }

  public void PlayValues(){
  ...
  Thread.CurrentThread.Abort();
  }

}

The reason why the thread is destroyed is because, every time the user clicks "Play" in the main form, X.Play() is called, so I need to either reuse the thread (I researched Monitor.Pulse(), but that gave me asynchronous call errors), or destroy it permanently each time it completes. 线程被销毁的原因是,每次用户点击主窗体中的“播放”时,都会调用X.Play(),所以我需要重用线程(我研究过Monitor.Pulse(),但是给了我异步调用错误),或者每次完成时永久销毁它。

Now, at the moment, the code works fine. 现在,目前,代码工作正常。 However, the fact that I'm consistently creating and destroying threads every time I have to play a macro is slightly concerning, and the ridiculous amount of GC calls is also worrying me. 但是,每次我必须播放一个宏时,我一直在创建和销毁线程这一事实略显令人担忧,而且大量的GC调用也让我感到担忧。

Can I get some pointers on threading, and how I might be able to do this better, without this setup? 我是否可以获得有关线程的一些指示,以及如何在没有此设置的情况下更好地完成此操作? As a point of fact, the secondary tab is a webpage, and the macros are executed on the webpage's form. 事实上,辅助选项卡是一个网页,宏在网页的表单上执行。

  • Edit: I don't know if I didn't make this clear, but the macro is using a mouse and keyboard simulator. 编辑:我不知道如果我没有说清楚,但宏是使用鼠标和键盘模拟器。 The other tab is a webbrowser setup, and it nests an applet inside, so I'm emulating the hardware functions in order to perform automated setups. 另一个选项卡是一个webbrowser设置,它将一个applet嵌入其中,所以我正在模拟硬件功能以执行自动设置。 This helps because I don't need to lock anything (all mouse and keyboard calls are operated by the simulators, and have no bearing on values controlled by the tertiary tab), I just need to be able to a) have the thread perform the same function whenever a user presses a button, and b) remove some of the excess materials. 这有帮助,因为我不需要锁定任何东西(所有鼠标和键盘调用都由模拟器操作,并且不受第三级选项卡控制的值的影响),我只需要能够a)让线程执行用户按下按钮时功能相同,b)移除一些多余的材料。

I was also informed that 'Thread.CurrentThread.Abort' is threadsafe and therefore a fine way to end a thread if you wanted to end it forever, but if I can have the thread repeat its functions instead of killing it, that'd be wonderful... 我还被告知'Thread.CurrentThread.Abort'是线程安全的,因此如果你想永久地结束它,这是结束线程的好方法,但如果我可以让线程重复其功能而不是杀死它,那就是精彩...

To reuse the play thread, you could use an AutoResetEvent that you Set() from the main thread. 要重用播放线程,可以使用主线程中Set()AutoResetEvent The same goes for when the thread is idle - the main thread prepares the data required to play, then Set() sa different AutoResetEvent , causing the play thread to start. 线程空闲时也是如此 - 主线程准备播放所需的数据,然后Set()不同的AutoResetEvent ,导致播放线程启动。

So the startPlayingAutoResetEvent in below example causes the thread to wait until the main thread tells it to "go", while the stopPlayingAutoResetEvent causes the play thread to respond to the main thread telling it to "stop" whenever it is not performing a step. 因此,下面示例中的startPlayingAutoResetEvent导致线程等待,直到主线程告诉它“go”,而stopPlayingAutoResetEvent导致播放线程响应主线程,告诉它在没有执行步骤时“停止”。

Main thread: 主线程:

// prepare data to play
startPlayingAutoResetEvent.Set();
// ...
stopPlayingAutoResetEvent.Set();

Play thread: 玩线程:

while (true)
{
    // wait for the main thread to signal "start"
    startPlayingAutoResetEvent.WaitOne();
    // ensure the stopPlaying is in an unsignalled state
    stopPlayingAutoResetEvent.Reset();

    // gather the data the main thread has prepared

    while (stepsToPlay)
    {
        // wait until main thread signals to stop OR timeout has elapsed
        if (stopPlayingAutoResetEvent.WaitOne(timeout))
        {
            // abort current run and put thread in idle mode, waiting for new commands
            break;
        }
        else
        {
            // play next step
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM