Многопоточные механизмы для выполнения некоторых длительных операций из кода winforms и связи с GUI - PullRequest
1 голос
/ 16 марта 2010

Чего я хочу достичь: Я хочу выполнить некоторые трудоемкие операции из моего приложения winforms MDI (C # - .NET).

Дочерняя форма MDI может создать поток с операцией, выполнение которой может занять много времени (от 0,1 секунды до даже получаса). Тем временем я хочу, чтобы пользовательский интерфейс реагировал на действия пользователя, включая манипулирование данными в какой-либо другой дочерней форме MDI. Когда операция завершается, поток должен уведомить дочерний объект MDI о том, что вычисления выполнены, чтобы потомок MDI мог выполнять постобработку.

Как мне этого добиться: Должен ли я использовать явные потоки (т.е. создавать явные потоки), пулы потоков? Или просто предложите свое решение. Нужно ли создавать темы переднего плана или фона?

А как поток взаимодействует с графическим интерфейсом в соответствии с предлагаемым вами решением?

Если вам известен рабочий пример, который обрабатывает аналогичную ситуацию, сделайте заметку.

Ответы [ 7 ]

4 голосов
/ 16 марта 2010

Я думаю, вы ищете класс BackgroundWorker . Пример

3 голосов
/ 16 марта 2010

Используйте класс BackgroundWorker. Это именно то, что вы ищете:

        BackgroundWorker backgroundWorker = new BackgroundWorker();
        backgroundWorker.DoWork += new DoWorkEventHandler(LongRunningCode);
        backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CallbackOnCompletion);
        backgroundWorker.RunWorkerAsync();

Кроме того, чтобы обновить пользовательский интерфейс из фонового потока, необходимо вызвать Invoke для вашего элемента пользовательского интерфейса.

1 голос
/ 16 марта 2010

Хотя объект BackgroundWorker является очевидным выбором, он может не подходить для длительного процесса, так как использует ThreadPool. Общепринятое мнение о ThreadPool заключается в том, что его нельзя использовать для длительных задач; в этих случаях рекомендуется явное создание потока.

Вы по-прежнему можете взаимодействовать с GUI, вызывая Invoke или BeginInvoke в форме (или любом из ее элементов управления), передавая делегата, который будет выполнять действия, связанные с GUI.

1 голос
/ 16 марта 2010

Это немного зависит.

В общем, Я согласен с BFree , что BackgroundWorker , вероятно, является лучшим вариантом здесь. Я делаю уведомление обратно в интерфейс простым и т. Д.

При этом единственная причина, по которой я публикую сообщения и задаю вопрос, хотите ли вы использовать BackgroundWorker, заключается в следующем:

, который может занять много времени (от 0,1 секунды до даже получаса) до завершения

BackgroundWorker использует поток ThreadPool для выполнения своей обработки. Это означает, что закрытие вашей формы заявки приведет к прекращению потока, поскольку это фоновый поток.

Если ваша «полчасовая» обработка «работа» - это то, что вы хотели бы продолжить работу, даже если форма закрыта, вы можете создать собственный поток переднего плана для выполнения этой операции и обрабатывать маршалинг пользовательского интерфейса. сами.

0 голосов
/ 16 марта 2010

Я рекомендую создать поток и использовать метод обратного вызова для связи с пользовательским интерфейсом.

Я привожу пример в этом решении, где вы также найдете примеры для других подходов: .NET Threading & Locks & Waiting .

0 голосов
/ 16 марта 2010

У вас есть много вариантов:

  1. Используйте BackgroundWorker напрямую, что в основном выполняет большую часть работы за вас, но длительная операция должна быть известна пользовательскому интерфейсу.
  2. Наследовать от System.ComponentModel.BackgroundWorker, что позволяет использовать операцию в качестве компонента и отделить логику от пользовательского интерфейса.
  3. Используйте Шаблон, основанный на событиях , который позволит лучше контролировать параметры и события.
  4. Используйте делегатов , если на самом деле нечего сообщать, кроме ned операции. Вы должны быть осторожны, так как метод обратного вызова не гарантированно выполняется в потоке пользовательского интерфейса.
0 голосов
/ 16 марта 2010

Если у вас очень ограниченное количество потоков (скажем, максимум 4), вы можете создать их самостоятельно. Если вам нужно, чтобы ими управляли так, как вы этого не хотите, то пул потоков - это одна из опций или .NET 4.0 System.Threading.Tasks пространство имен.

Вам, вероятно, нужно будет использовать делегатов. Вот пример того, что пишет в пользовательский интерфейс, и того, что читает из пользовательского интерфейса:

    delegate void SetResultsTextCallback(string text);
    delegate string GetIterationCountCallback();

    private void SetResultsText(string text)
    {
        if (this.ResultsBox.InvokeRequired)
        {
            var d = new SetResultsTextCallback(SetResultsText);
            this.Invoke(d, new object[] { text });
        }
        else
        {
            this.ResultsBox.Text = text;
        }
    }

    private string GetIterationCount()
    {
        if (this.RepetitionSelector.InvokeRequired)
        {
            var del = new GetIterationCountCallback(GetIterationCount);
            IAsyncResult result = del.BeginInvoke(null, null);
            return del.EndInvoke(result);
        }
        else
        {
            return RepetitionSelector.SelectedItem.ToString();
        }
    }

В этом примере ResultsBox - это TextBox, а RepetitionSelector - это комбинированный список.

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