Могут ли потоки вести себя как BackgroundWorkers (winForms)? - PullRequest
2 голосов
/ 03 декабря 2010

Я пытаюсь работать с Threadding, и мне кажется, что это подозрительно сложно (возможно, я делаю это неправильно).

Я хочу загрузить файл внутри BackgroundWorker, и пока это происходит, «отправлять» каждую новую строку в отдельный поток (не bgWorker). Я использую BlockingCollection и Add() каждой строки, затем я хочу Take() их и обработать в другом потоке.

Теперь все просто с BgWorker; но почему невозможно (не так ли?) просто объявить новый поток в Form1.cs и заставить его работать как BgWorker? Другими словами, почему вы должны создать отдельный WorkerClass (http://msdn.microsoft.com/en-us/library/7a2f3ay4(VS.80).aspx)?

Я спрашиваю об этом, потому что вы можете получить доступ к штрафе BlockingCollection из BackgroundWorker, но вы не можете сделать это из отдельного WorkerClass (так как это простой отдельный класс). (Так в чем же смысл BlockingCollection, если вы не можете использовать его для того, что он имел в виду?)

Кроме того, у BgWorkers есть событие / метод ReportProgress(...). Насколько я знаю, если вы используете этот пример msdn, у вас не будет приседа в вашей ветке.

Что мне здесь не хватает? Пожалуйста, помогите.


PS: Прежде чем прыгать и сказать мне, что отправлять строки в другой поток не в коей мере эффективнее, знайте, что я делаю это как учебное упражнение. Попытка выяснить, как потоки работают в C # и как вы синхронизируете / общаетесь между ними / и с ними (и / или bgWorkers).

Ответы [ 2 ]

3 голосов
/ 03 декабря 2010

Отвечая конкретно, почему работать с потоками сложнее, чем с фоновым рабочим ....

Фоновый рабочий - это на самом деле метод создания другого потока, упакованного в более простой в использовании пакет. Причина работы с потоками напрямую сложнее, потому что она ближе к реальной.

Для аналогичного сравнения использование System.Net.Mail для отправки электронной почты - это просто упрощенный способ создания соединений с сокетами и т. Д. Под капотом классы System.Net.Mail выполняют детальную работу. Аналогично, под капотом BackgroundWorker выполняет детальную работу по обработке потоков.

На самом деле документация MSDN для объекта backgroundWorker начинается следующим образом:

Класс BackgroundWorker обновлен: Сентябрь 2010

выполняет операцию на отдельном нить.

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

Итак, если класс backgroundworker должен облегчить работу с потоками, почему люди хотят работать с потоками напрямую? Из-за проблемы у вас есть. Иногда «дружеская обертка» приводит к потере контроля.

Редактировать - добавлено

В комментариях вы спрашиваете о синхронизации потоков. Эта статья освещает это довольно хорошо.

http://msdn.microsoft.com/en-us/magazine/cc164037.aspx

и эта статья явно отвечает на вопрос «общение между потоками».

http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework/topic63233.aspx

2 голосов
/ 03 декабря 2010

Чтобы ответить на ваш вопрос в заголовке, да "нормальные" темы могут действовать как BackgroundWorker темы.Вам просто нужно создать больше кода для проводки самостоятельно.

Я написал простое приложение для сканирования моей музыкальной коллекции с использованием созданного вручную потока.Основное тело потока - это метод, который перебирает все папки в указанном корне и запускает событие каждый раз, когда встречает папку, содержащую некоторые mp3-файлы.

Я подписываюсь на это событие в основномформы моего приложения и обновите DataGridView с новой информацией.

Таким образом, поток запускается с помощью следующего кода:

this.libraryThread = new Thread(new ThreadStart(this.library.Build)) { IsBackground = true };

// Disable all the buttons except for Stop which is enabled
this.EnableButtons(false);

// Find all the albums
this.libraryThread.Start();

Метод, предоставленный ThreadStart, выполняет некоторую служебную работу изатем вызывает метод, который выполняет эту работу:

private void FindAlbums(string root)
{
    // Find all the albums
    string[] folders = Directory.GetDirectories(root);
    foreach (string folder in folders)
    {
        if (this.Stop)
        {
            break;
        }

        string[] files = Directory.GetFiles(folder, "*.mp3");
        if (files.Length > 0)
        {
            // Add to library - use first file as being representative of the whole album
            var info = new AlbumInfo(files[0]);
            this.musicLibrary.Add(info);
            if (this.Library_AlbumAdded != null)
            {
                this.Library_AlbumAdded(this, new AlbumInfoEventArgs(info));
            }
        }

        this.FindAlbums(folder);
    }
}

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

Я подписываюсь на эти события в основной форме:

this.library.Library_AlbumAdded += this.Library_AlbumAdded;
this.library.Library_Finished += this.Library_Finished;

и в этих методах добавьте новый альбом в сетку:

private void Library_AlbumAdded(object sender, AlbumInfoEventArgs e)
{
    this.dataGridView.InvokeIfRequired(() => this.AddToGrid(e.AlbumInfo));
}

и завершите работу (что включает кнопки и т. Д.):

private void Library_Finished(object sender, EventArgs e)
{
    this.dataGridView.InvokeIfRequired(() => this.FinalUpdate());
}

Как вы можетевидите, это большая работа, которая была бы намного проще, если бы я использовал BackgroundWorker.

...