如何在后台线程上运行我的任务? | c#| SSH

时间:2018-01-29 20:54:17

标签: c# multithreading ssh delegates invoke

我正在尝试在我的Telnet / SSH程序的后台运行一系列任务。遗憾的是,我似乎无法找到如何在后台运作。

我尝试使用任务

Task ReindexStock = new Task(delegate
        {
            this.Invoke(new Action(() =>
            {
                btnReindexStock.PerformClick();
                txtBoxInput.Text = command[1];
                ExecuteCommand();
            }
            ));
        });
        ReindexStock.Start();
        ReindexStock.Wait();

        Task Product_attribute = new Task(delegate
        {
            this.Invoke(new Action(() =>
            {
                btnReindexProduct_Attribute.PerformClick();
                txtBoxInput.Text = command[2];
                ExecuteCommand();
            }
          ));
        });
        Product_attribute.Start();
        Product_attribute.Wait();

我还尝试了主题

new Thread(() =>
    {
        btnReindexStock.PerformClick();
        txtBoxInput.Text = command[1];
        ExecuteCommand();
    }).Start();
new Thread(() =>
    {
        btnReindexProduct_Attribute.PerformClick();
        txtBoxInput.Text = command[2];
        ExecuteCommand();
    }).Start();

以及这个(从网上摘下这个,希望它会起作用):

          ThreadPool.QueueUserWorkItem(delegate
      {
          btnReindexStock.PerformClick();
          txtBoxInput.Text = command[1];
          ExecuteCommand();
      });
      ThreadPool.QueueUserWorkItem(delegate
      {
          btnReindexProduct_Attribute.PerformClick();
          txtBoxInput.Text = command[2];
          ExecuteCommand();
      });

但由于某种原因,我的程序在执行ExecuteCommand时仍会冻结(

  var cmd = SSH.client.CreateCommand(txtBoxInput.Text);
        var result = cmd.Execute();
        this.Invoke(new Action(() =>
        {
            rTxtBoxOutput.Text += result;

            var reader = new StreamReader(cmd.ExtendedOutputStream);
            rTxtBoxOutput.Text += "\n" + reader.ReadToEnd();
        }
        ));

我已经在backgroundworker_doWork中尝试了几件事,但是它们似乎都没有工作..我试图开始这样的新线程

new Thread(new ThreadStart(ReindexAll)).Start();

也是这样,但我想这实际上是相同但更大

Thread t = new Thread(new ThreadStart(ReindexAll));
            t.Start();
            t.IsBackground = true;

Task.Factory.StartNew(() => ReindexAll());

以及简单明了的

ReindexAll();

但正如我之前所说的那样,在我执行命令的那一刻,程序冻结了。

现在我的问题是,如果有人能够告诉我我做错了什么并希望能帮助我

2 个答案:

答案 0 :(得分:0)

从大多数示例中,您似乎都在尝试单击后台线程上的按钮以开始执行任何任务。

所有UI只能在UI线程上工作。我想,大多数这几乎肯定会导致错误。如果您尝试严格按照UI线程执行某些操作,则可以。但是,您不应该在另一个线程上触发按钮来执行此操作。通常来说,按钮应该只由您的操作员触发。

如果您需要在没有操作员参与的情况下完成一些工作,您可以在应用程序启动时执行所有操作,或者您可以设置计时器并通过它启动工作。同样,这不应该触发按钮,而是工作本身。

答案 1 :(得分:0)

好的,首先 - 我建议简化你正在创建任务的东西。不要试图编写内联委托,只需将Task的代码分解为单独的函数,然后让Task引用它。更简单,更清洁。

Task myTask = new Task(TaskCode);

// elsewhere ...

private void TaskCode()
{
    // stuff
}

此时,在创建myTask之后,您只需调用myTask.Start()就可以了。

现在,这只是问题的一半。如果你试过这个:

private void TaskCode()
{
    SomeGuiControl.Text = "something";
}

...你将得到一个错误,你无法从非gui线程更新GUI控件。但是,可以使用Invoke或BeginInvoke将消息传递给GUI线程以处理更新(请参阅:Writing to a TextBox from another thread?)最简单的类似于:

txtResults.BeginInvoke(new Action(() => txtResults.Text = DateTime.Now.ToString() + " Hello World"));

最后,还有一个额外的警告非常重要。你不应该在GUI线程上执行Task.Wait()。为什么?因为在Task.Wait()完成之前,所有的GUI事件都不会启动 - 这意味着,如果你在整个任务中更新了GUI卡,它就不会出现,直到完成所有操作!请记住,我们的想法是尽可能快地完成GUI线程的代码。启动线程并退出 - 保持GUI线程可以自由处理其他事件(用户或其他方式。)

把它们放在一起?以下是我为此问题创建的WinForm上的示例代码:

private void btnSmallJob_Click(object sender, EventArgs e)
{
    Task myTask = new Task(SmallTaskCode);
    myTask.Start();  // NOTE: I'm NOT doing a wait() on this task; don't want to hold up the GUI thread.

}

private void SmallTaskCode()
{
    System.Threading.Thread.Sleep(1000);
    txtResults.BeginInvoke(new Action(() => txtResults.Text += DateTime.Now.ToString() + " Small Job" + Environment.NewLine));
    System.Threading.Thread.Sleep(1000);
}

Task singleInstanceOfLargeJob;

private void btnLargeJob_Click(object sender, EventArgs e)
{
    if (this.singleInstanceOfLargeJob == null || this.singleInstanceOfLargeJob.Status != TaskStatus.Running)
    {
        singleInstanceOfLargeJob = new Task(LargeTaskCode);
        singleInstanceOfLargeJob.Start();  // NOTE: I'm NOT doing a wait() on this task; don't want to hold up the GUI thread.
        return;
    }
    MessageBox.Show("Sorry, you can only have one instance of the large job running at once!");
    // this job should only have one instance running at a time!
}

private void LargeTaskCode()
{
    System.Threading.Thread.Sleep(1000);
    txtResults.BeginInvoke(new Action(() => txtResults.Text += DateTime.Now.ToString() + " Big Job A" + Environment.NewLine));
    System.Threading.Thread.Sleep(1000);
    txtResults.BeginInvoke(new Action(() => txtResults.Text += DateTime.Now.ToString() + " Big Job B" + Environment.NewLine));
    System.Threading.Thread.Sleep(1000);
    txtResults.BeginInvoke(new Action(() => txtResults.Text += DateTime.Now.ToString() + " Big Job C" + Environment.NewLine));
    System.Threading.Thread.Sleep(1000);
}

基本上,我有两种不同的方式。上半部分只是一个简单的,开始完成的线程。第二个跟踪任务,并且不允许两个作业同时运行。

无论如何,希望有所帮助!