我正在尝试在我的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();
但正如我之前所说的那样,在我执行命令的那一刻,程序冻结了。
现在我的问题是,如果有人能够告诉我我做错了什么并希望能帮助我
答案 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);
}
基本上,我有两种不同的方式。上半部分只是一个简单的,开始完成的线程。第二个跟踪任务,并且不允许两个作业同时运行。
无论如何,希望有所帮助!