C# - 线程的行为可以像BackgroundWorkers(winForms)吗?

时间:2010-12-03 19:59:49

标签: c# multithreading backgroundworker

我正在尝试与Threadding合作,在我看来,这似乎很难(我可能做错了)。

我想在BackgroundWorker内加载一个文件,当发生这种情况时,将每个新行“发送”到一个单独的线程(而不是bgWorker)。我在每行使用BlockingCollectionAdd(),然后我想Take()他们并在另一个帖子中处理它们。

现在,BgWorker的一切都很简单;但为什么在Form1.cs中声明一个新线程并让它像BgWorker一样执行它是不可能的(不是吗?)换句话说,为什么必须创建一个单独的WorkerClass(http://msdn.microsoft.com/en-us/library/7a2f3ay4(VS.80).aspx)?

我问这个是因为,你可以从BackgroundWorker中访问你的BlockingCollection罚款,但是你不能从一个单独的WorkerClass中做到这一点(因为它是一个普通的独立类)。 (那么BlockingCollection的重点是什么,如果你不能将它用于它的含义?)

此外,BgWorkers有一个ReportProgress(...)事件/方法。据我所知,如果你使用那个msdn例子,你的线程中没有下蹲。

我在这里缺少什么?请帮忙。


PS:在你跳之前告诉我,将线路发送到另一个线程并不是更有效率,但要知道我这样做是为了学习练习。试图弄清楚线程如何在C#中工作以及如何在/与它们(和/或bgWorkers)之间进行同步/通信。

2 个答案:

答案 0 :(得分:3)

具体回答为什么使用线程比使用后台工作者更困难....

backgroundworker实际上是一种创建另一个线程的方法,该线程包含在一个更易于使用的包中。直接使用线程的原因更难,因为它更接近真实的东西。

对于类似的比较,使用System.Net.Mail发送电子邮件只是创建套接字连接等的简化方法......在幕后,System.Net.Mail类执行详细的工作。同样,在幕后,BackgroundWorker完成了处理线程的详细工作。

事实上,backgroundWorker对象的MSDN文档开头如下:

  

BackgroundWorker类已更新:   2010年9月

     

单独执行操作   线程。

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

答案 1 :(得分:2)

要在标题中回答您的问题,是的“正常”线程可以像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,这将是一项非常简单的工作。