Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#-线程是否可以像后台工作程序(winForms)那样工作?_C#_Multithreading_Backgroundworker - Fatal编程技术网

C#-线程是否可以像后台工作程序(winForms)那样工作?

C#-线程是否可以像后台工作程序(winForms)那样工作?,c#,multithreading,backgroundworker,C#,Multithreading,Backgroundworker,我正在尝试使用线程,在我看来,这似乎有点困难(我可能做错了) 我想在BackgroundWorker中加载一个文件,在加载过程中,将每一行新行“发送”到一个单独的线程(而不是bgWorker)。我正在使用BlockingCollection和Add()每一行,然后我想Take()并在另一个线程中处理它们 现在,对于BgWorker,一切都很简单;但是为什么不可能(不是吗?)在Form1.cs中声明一个新线程并让它像BgWorker一样执行呢?换句话说,为什么必须创建一个单独的WorkerClas

我正在尝试使用
线程
,在我看来,这似乎有点困难(我可能做错了)

我想在
BackgroundWorker
中加载一个文件,在加载过程中,将每一行新行“发送”到一个单独的线程(而不是bgWorker)。我正在使用
BlockingCollection
Add()
每一行,然后我想
Take()
并在另一个线程中处理它们

现在,对于BgWorker,一切都很简单;但是为什么不可能(不是吗?)在
Form1.cs
中声明一个新线程并让它像BgWorker一样执行呢?换句话说,为什么必须创建一个单独的WorkerClass()

我这样问是因为,您可以从BackgroundWorker内部访问BlockingCollection,但不能从单独的Worker类访问它(因为它是一个普通的单独类)。(那么,如果你不能将BlockingCollection用于它的意义,那么BlockingCollection的意义何在?)

此外,BgWorkers还有一个
ReportProgress(…)
event/method。据我所知,如果您使用那个msdn示例,您的线程中就不会有深蹲

我错过了什么?请帮忙



附言:在你跳起来告诉我把行发送到另一个线程没有任何效率之前,请知道我这样做是为了学习。试图弄清楚线程在C#中是如何工作的,以及如何在它们(和/或bgWorkers)之间进行同步/通信。

具体回答为什么使用线程比使用后台worker更困难

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

对于类似的比较,使用System.Net.Mail发送电子邮件只是创建套接字连接等的一种简化方法。。。在后台,System.Net.Mail类完成了详细的工作。同样,在引擎盖下,后台工作人员负责处理线程的详细工作

事实上,backgroundWorker对象的MSDN文档开始时是这样的:

BackgroundWorker类已更新: 2010年9月

在单独的磁盘上执行操作 线

那么,如果backgroundworker类应该使线程更容易,为什么人们希望直接使用线程呢?因为你的问题。有时,“友好包装”会导致失去精细控制

编辑-添加

您在评论中询问的是线程同步。这篇文章很好地介绍了它

本文明确回答了“线程间通信”


要回答标题中的问题,是的“正常”线程可以像
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));
}
并结束(可重新启用按钮等):


正如你所看到的,如果我使用了
BackgroundWorker

,这将是一项非常简单的工作。如果你想了解线程是如何工作的,那么就不要使用BGW,它会让你避免太多麻烦。如果你使用BlockingCollection,那么你就在Fx4上,你应该研究任务(TPL)而不是线程。@Henk;伙计。谢谢(我仍将研究线程,但)感谢您告诉我有关
System.Threading.Tasks
的存在。让记录显示这是“我想要的”(BlockingCollection+Tasks):那太好了。“真实的东西”在我看来并不比同样的东西有什么优势,只是更好、更容易。。不管怎样,你(可以吗?)如何在普通线程上使用BlockingCollection?我遇到的问题是,我能够在BgWorkers之间进行良好的通信,并且我看不到任何直接/特定的方法来使用常规线程进行通信。@Twodordan-使用对象作为参数触发事件。ChrisF,你能详细说明一下吗?(我知道什么是事件,但它们如何帮助我跨线程发送内容?)这是一个非常有用的示例。(解释我的“活动将如何帮助你”问题)。我不明白这个.library.Build是什么。图书馆是一门课吗?还是什么?@Twodordan-这是我创建的一个代表媒体库的类。我想这个名字会更好。
FindAlbums
方法驻留在该类中。非常感谢。现在一切都有了意义:)
private void Library_Finished(object sender, EventArgs e)
{
    this.dataGridView.InvokeIfRequired(() => this.FinalUpdate());
}