C#如何处理线程切换?

时间:2012-03-01 10:31:48

标签: c# winforms multithreading label

我正在开发一个应用程序,其中两个线程同时从一个类执行一个方法。此方法执行一些复杂的计算,结果显示在WinForm中。

所以我的班级看起来像:

class Comp_func
{
    /* Constructor */
    public Comp_func()
    {
    }

    public void THE_Complex_func(string One, Int16 Two, Int32 Three)
    {
        Calculate_this(One);
        Thread.Sleep(10);
        Calculate_that(Two);
        Thread.Sleep(10);
        Calculate_thatThat(Three);
        Thread.Sleep(10);
        Update_lable_in_form(value);
        Thread.Sleep(10);
    }
}

每个线程更新WinForm中的不同Label所以,我希望没有关于线程同步的问题(因为我使用了线程安全方法)。

我的需求是这些更新应该同时发生(至少似乎同时发生)。

当用户点击表单中的“计算”按钮时,我会执行以下操作:

Comp_func Func1_class = new Comp_func();
Comp_func Func2_class = new Comp_func();

Thread Func1_Thread = new Thread(() => Func1_class.Start_Test("Blah", 2,3));
Thread Func2_Thread = new Thread(() => Func2_class.Start_Test("BlahBlah", 4,5));

//Func1_Thread.Priority = ThreadPriority.Highest;  /* Deleted after Comments */
   // Func2_Thread.Priority = ThreadPriority.Highest;  /* Deleted after Comments */


Func1_Thread.Start();
Func2_Thread.Start();

/*
  //  Removed after Comments 

// Let only Threads Run
 while(true)
{
    Application.DoEvent();
    Update();
}

for(count = 0; count < 100; count++)
 {  
    console.WriteLine("I WON'T USE WHILE(1) loops with DOEVENTS");
 }

*/

我的问题是,当线程1的执行完成时,它会更新Label,然后线程2启动并执行。

为了避免这种行为,我几乎在每一行之后写了Thread.Sleep();。它仍然表现得好像windows没有注意切换!

知道为什么会这样吗?

提前致谢!

3 个答案:

答案 0 :(得分:4)

您的代码示例非常不完整 - 因此很难看到发生了什么。

我的第一个评论是你的点击处理程序不应该有一个无限循环 - 实际上你根本不需要while(true)..DoEvent()代码

为了响应您的要求,两个标签同时更新,最好的办法是让线程在更新UI之前加入 - 一种方法是创建一个开始其他两个线程的BackgroundWorker,Join( )s,然后使用两个结果更新UI - 根据您运行的.net版本,您可以使用Tasks库以较少的代码执行此操作。

这是一个相当粗略的实现(如果您没有可用的任务库):

    private void button1_Click(object sender, System.EventArgs e)
    {
        BackgroundWorker master= new BackgroundWorker();
        master.DoWork += (sender1, e1) =>
                              {
                                  Thread t1 = new Thread(Func1_class.Start_Test);
                                  Thread t2 = new Thread(Func1_class.Start_Test);
                                  t1.Start();
                                  t2.Start();
                                  t1.Join();
                                  t2.Join();
                              };
        master.RunWorkerCompleted += (sender2, e2) =>
                                          {
                                              label1.Text = "text";
                                              label2.Text = "text";
                                          };
        master.RunWorkerAsync();
    }

答案 1 :(得分:2)

按照@dice的建议摆脱sleep()调用和DoEvents()循环 - 无论你认为它们有多少,它们都没有帮助。如果你正确调用/ BeginInvoke-标签更改,你应该没问题 - 只需退出OnClick事件处理程序。您不应该在GUI事件处理程序中等待。

重复 - 不要尝试在GUI事件处理程序中等待。

您拥有多少个处理器核心,为什么提高了工作线程的优先级?如果你只有一个CPU而你在Func1_Thread上启动一个CPU密集型任务,它将使用100%CPU运行,直到它自动停止或Windows反饥饿算法在30秒后给其他线程几个周期。这会给人一种序列化的印象。

将线程提升到高优先级然后插入sleep()调用只是......好吧,就是不要这样做!

答案 2 :(得分:1)

你真的不了解线程。

您无法确定操作系统将如何处理线程的执行。 如果你想同时更改标签,你必须自己做。

例如,在你的超级函数结束时引发一个事件,例如,让我们称之为SuperCalcDone。 在SuperCalcDone处理程序上,只需检查所有计算是否完成,然后更新标签。