Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在一个按钮单击功能中访问两个线程_C#_Multithreading_Winforms - Fatal编程技术网

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..
    
或者,您也可以尝试一些漂亮的包装,比如TPL框架,如Sheridan的回答所示

当然,您必须小心从其他新线程运行的内部触摸UI元素。谢里登的回答已经通过第三方物流的方式涵盖了这一点。您必须手动使用Invoke/BeginInvoke将与UI相关的代码反弹回UI线程。在您当前的代码中,您已经有了它,但是在那个地方,它不是必需的,因为_clickhandler方法显然已经在UI线程中运行了

因此,您当前的示例可以简化为:

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..
    
或者,您也可以尝试一些漂亮的包装,比如TPL框架,如Sheridan的回答所示

当然,您必须小心从其他新线程运行的内部触摸UI元素。谢里登的回答已经通过第三方物流的方式涵盖了这一点。您必须手动使用Invoke/BeginInvoke将与UI相关的代码反弹回UI线程。在您当前的代码中,您已经有了它,但在那个地方,它是<