C# 在一个按钮单击功能中访问两个线程
这并没有向我抛出任何错误,但在执行第一个线程之后,它并没有执行第二个线程。我做错什么了吗 下面是我的代码: 我的按钮点击功能:C# 在一个按钮单击功能中访问两个线程,c#,multithreading,winforms,C#,Multithreading,Winforms,这并没有向我抛出任何错误,但在执行第一个线程之后,它并没有执行第二个线程。我做错什么了吗 下面是我的代码: 我的按钮点击功能: private void ImportBothButtonclick(object sender, EventArgs e) { // Get the currently selected manufacturer from the combo box var selected = comboBox.SelectedItem;
private void ImportBothButtonclick(object sender, EventArgs e)
{
// Get the currently selected manufacturer from the combo box
var selected = comboBox.SelectedItem;
// Do we have one?
if (selected != null)
{
// Extract the combo record
var val= (ComboBoxItem)selected;
// Do we have one?
if (val != null)
{
// yes
// Make this on a seperate thread so that the UI continues to work
Invoke(new System.Action(() =>
{
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
var thread = new Thread(DoFunction1);
thread.Start(val);
}));
Invoke(new System.Action(() =>
{
button1.Enabled = false;
button2.Enabled = false;
button3Enabled = false;
var thread = new Thread(DoFunction2);
thread.Start(val);
}));
}
}
}
也许你可以这样做
Task.Factory.StartNew(new Action(() =>
{
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
}), new CancellationToken(), TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext()).
ContinueWith(new Action(() => DoFunction1)).
ContinueWith(new Action(() =>
{
button1.Enabled = false;
button2.Enabled = false;
button3Enabled = false;
}), TaskScheduler.FromCurrentSynchronizationContext()).
ContinueWith(new Action(() => DoFunction2));
也许你可以这样做
Task.Factory.StartNew(new Action(() =>
{
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
}), new CancellationToken(), TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext()).
ContinueWith(new Action(() => DoFunction1)).
ContinueWith(new Action(() =>
{
button1.Enabled = false;
button2.Enabled = false;
button3Enabled = false;
}), TaskScheduler.FromCurrentSynchronizationContext()).
ContinueWith(new Action(() => DoFunction2));
这些行动是行不通的。这些操作是在您当前所在的同一线程上调用的 线程当前并行运行。如果希望这些线程以串行方式运行,而不是在gui线程上运行,可以执行以下操作: 这是非任务版本。
// not allowed on a non-gui thread.
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
new Thread(() =>
{
DoFunction1();
DoFunction2();
// execute this on the gui thread. (winforms)
this.Invoke(new Action( delegate
{
button1.Enabled = true;
button2.Enabled = true;
button3.Enabled = true;
}));
}).Start();
如果要并行运行它们,但请等待它们完成:
// not allowed on a non-gui thread.
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
new Thread(() =>
{
ManualResetEvent wait1 = new ManualResetEvent(false);
ManualResetEvent wait2 = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem((state) =>
{
DoFunction1();
wait1.Set();
});
ThreadPool.QueueUserWorkItem((state) =>
{
DoFunction2();
wait2.Set();
});
ManualResetEvent.WaitAll(new WaitHandle[] { wait1, wait2 });
this.Invoke(new Action( delegate
{
// execute this on the gui thread. (winforms)
button1.Enabled = true;
button2.Enabled = true;
button3.Enabled = true;
}));
}).Start();
但这可以更容易地使用任务。任务并行性(任务并行库)这些操作不会起作用。这些操作是在您当前所在的同一线程上调用的 线程当前并行运行。如果希望这些线程以串行方式运行,而不是在gui线程上运行,可以执行以下操作: 这是非任务版本。
// not allowed on a non-gui thread.
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
new Thread(() =>
{
DoFunction1();
DoFunction2();
// execute this on the gui thread. (winforms)
this.Invoke(new Action( delegate
{
button1.Enabled = true;
button2.Enabled = true;
button3.Enabled = true;
}));
}).Start();
如果要并行运行它们,但请等待它们完成:
// not allowed on a non-gui thread.
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
new Thread(() =>
{
ManualResetEvent wait1 = new ManualResetEvent(false);
ManualResetEvent wait2 = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem((state) =>
{
DoFunction1();
wait1.Set();
});
ThreadPool.QueueUserWorkItem((state) =>
{
DoFunction2();
wait2.Set();
});
ManualResetEvent.WaitAll(new WaitHandle[] { wait1, wait2 });
this.Invoke(new Action( delegate
{
// execute this on the gui thread. (winforms)
button1.Enabled = true;
button2.Enabled = true;
button3.Enabled = true;
}));
}).Start();
但这可以更容易地使用任务。任务并行性(任务并行库)请澄清您观察到的确切问题是什么 根据您目前所说的,问题在于“第二个线程不在第一个线程之后运行” 所以,让我来回答这个问题 您的代码几乎正常。您忽略了一件重要的事情:您的代码“new thread/thread.start()”实际上启动了一个新线程,然后它不会等待该线程执行或完成 线路:
new thread(f1).Start()
new thread(f2).Start()
不会“在线程1上运行F1,然后在线程2上运行F2”。相反,它们将“开始在线程1上运行F1,并立即在线程2上运行F2”
要在F1完全完成后才执行F2,必须以某种方式将两者“链接”在一起:
- 您可以创建简单的“议程”方法并运行它:
private void doAllTasks() { f1(); f2(); } new thread(doAllTasks).Start()
- 您可以尝试通过lambdas动态地“链接”它们,这实际上与上面相同:
new thread(() => { f1(); f2(); ).Start()
- 实际上,您可以立即运行这两个线程,但是让F2加入[wait],直到F1的线程结束
var th1 = new thread(f1); var th2 = new thread(() => {th1.Join(); f2();} ) th1.Start(); th2.Start(); // note that this code is NOT perfect, there's some error handling to do here, etc..
private void ImportBothButtonclick(object sender, EventArgs e)
{
var selected = comboBox.SelectedItem;
if (selected != null)
{
var val= (ComboBoxItem)selected;
if (val != null)
{
// no Invoke needed, "button_click" handlers
// are already on UI thread, so touching UI things is OK
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
// starting a new thread also does not need Invoke
var thread = new Thread(DoAllFunctions);
thread.Start(val);
}
}
}
private void DoAllFunctions(object something)
{
DoFunction1(something);
DoFunction2(something);
// button1.Enabled = true; - cannot do it here because they are UI
// button2.Enabled = true; - and DoAll is run from other thread.
// button3.Enabled = true; - you must bounce that back to UI thread.
LetTheUIKnowJobsAreFinished(); // <- performed here
}
private void LetTheUIKnowJobsAreFinished()
{
Invoke(new Action(()=>{
button1.Enabled = true;
button2.Enabled = true;
button3.Enabled = true;
});
}
private void importboth按钮单击(对象发送方,事件参数e)
{
var selected=comboBox.SelectedItem;
如果(已选择!=null)
{
var val=(ComboBoxItem)已选中;
如果(val!=null)
{
//无需调用“按钮单击”处理程序
//已经在UI线程上,所以触摸UI内容是可以的
按钮1.启用=错误;
按钮2.Enabled=false;
按钮3.Enabled=false;
//启动新线程也不需要调用
var线程=新线程(DoAllFunctions);
线程启动(val);
}
}
}
私有void DoAllFunctions(对象某物)
{
do1(某物);
do2(某物);
//button1.Enabled=true;-无法在此处执行此操作,因为它们是UI
//button2.Enabled=true;-并且DoAll从其他线程运行。
//button3.Enabled=true;-必须将其反弹回UI线程。
让UIKnown作业已完成();//{
按钮1.启用=真;
按钮2.Enabled=true;
按钮3.Enabled=true;
});
}
另外,作为最后一点,请查看System.ComponentModel中的BackgroundWorker
。它有一组非常好的事件/回调,使所有线程交叉都非常容易
(顺便说一句:这段代码不可用。它只是一个草图。你会发现打字错误、缺少冒号、缺少try-catch等等!)请澄清你观察到的确切问题是什么 根据您目前所说的,问题在于“第二个线程不在第一个线程之后运行” 所以,让我来回答这个问题 您的代码几乎正常。您忽略了一件重要的事情:您的代码“new thread/thread.start()”实际上启动了一个新线程,然后它不会等待该线程执行或完成 线路:
new thread(f1).Start()
new thread(f2).Start()
不会“在线程1上运行F1,然后在线程2上运行F2”。相反,它们将“开始在线程1上运行F1,并立即在线程2上运行F2”
要在F1完全完成后才执行F2,必须以某种方式将两者“链接”在一起:
- 您可以创建简单的“议程”方法并运行它:
private void doAllTasks() { f1(); f2(); } new thread(doAllTasks).Start()
- 您可以尝试通过lambdas动态地“链接”它们,这实际上与上面相同:
new thread(() => { f1(); f2(); ).Start()
- 实际上,您可以立即运行这两个线程,但是让F2加入[wait],直到F1的线程结束
var th1 = new thread(f1); var th2 = new thread(() => {th1.Join(); f2();} ) th1.Start(); th2.Start(); // note that this code is NOT perfect, there's some error handling to do here, etc..