Как C # управляет переключением потоков? - PullRequest
0 голосов
/ 01 марта 2012

Я работаю над приложением, в котором два потока одновременно выполняют метод из класса.Этот метод выполняет некоторые сложные вычисления, и результат отображается в 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);
    }
}

Каждый поток обновляется по-разному Label в WinForm, поэтому я ожидаюнет проблем с синхронизацией потоков (так как я использовал Thread Safe Methods).

Мне нужно, чтобы эти обновления происходили одновременно (по крайней мере, кажется, что они происходят одновременно).

Когда пользователь нажимает кнопку "Рассчитать" в моей форме, я делаю:

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 ]

4 голосов
/ 01 марта 2012

Ваш пример кода довольно неполный - поэтому трудно понять, что происходит.

Первый комментарий, который я хотел бы получить, заключается в том, что у вас не должно быть бесконечного цикла в обработчике кликов - фактически выкод while(true)..DoEvent() вообще не нужен

В ответ на ваше требование одновременного обновления двух меток лучше всего объединить потоки перед обновлением пользовательского интерфейса - один из способов сделать эточтобы создать BackgroundWorker, который запускает два других потока, объедините их, а затем обновите интерфейс с двумя результатами - в зависимости от версии .net, с которой вы работаете, вы можете использовать библиотеку задач для этогоменьше кода.

вот довольно грубая реализация (если у вас нет библиотеки задач):

    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();
    }
2 голосов
/ 01 марта 2012

Избавьтесь от вызовов sleep () и цикла DoEvents (), как предлагает @dice, - они не помогают, независимо от того, насколько вы о них думаете.Если вы правильно вызываете / начинаете вызывать изменения метки, у вас все должно быть в порядке - просто выйдите из обработчика событий OnClick.Вы не должны ждать в обработчиках событий GUI.

Repeat - не пытайтесь ждать в обработчике событий GUI.

Сколько у вас процессорных ядер и почему вы повысили приоритетиз рабочих тем?Если у вас только один ЦП, и вы запускаете задачу с интенсивным ЦП в Func1_Thread, она будет выполняться с использованием 100% ЦП до тех пор, пока не остановится сама, или алгоритм анти-голодания Windows не даст другим потокам несколько циклов через 30 секунд.Это создаст впечатление сериализации.

Повышение потоков до высокого приоритета и последующая вставка вызовов sleep () - это просто ... ну, просто не делайте этого!

1 голос
/ 01 марта 2012

Есть кое-что, что вы действительно не понимаете в темах.

Вы не можете точно знать, как ОС будет обрабатывать выполнение потоков. Если вы хотите изменить метки одновременно, вам придется сделать это самостоятельно.

Например, в конце вашей суперфункции вызовите событие, например, назовем его SuperCalcDone. В вашем обработчике SuperCalcDone просто проверьте, все ли вычисления выполнены, а затем обновите метки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...