c# - 在 C# 中使用多线程的正确方法

标签 c# wpf multithreading synchronization

我正在用 做一个小下载管理器C# WPF .

在我的逻辑中,有一个主线程(用于 UI)、一个用于管理连接的线程和一个用于每次下载的线程,直到我使用 定义的最大下载数。信号量 .

每次用户想要下载东西时,它都会添加一个自定义对象 DownloadDetails在共享队列中,连接线程将其出列并让另一个线程进行实际下载。

对于单个文件,它工作正常,但对于多个文件,看起来更多线程尝试下载同一个文件,尝试在本地驱动器上写入同一个文件并在写入流时崩溃。

这是我实现的一些片段

主要 形式:

private Thread connectionManager;

当单击下载时,我添加了新的下载(它们都是正确的,我检查了它)并仅在连接线程尚未启动时才启动它:
downloadList.Enqueue(newDownload);
if (connectionManager == null || !connectionManager.IsAlive)
{
   connectionManager = new Thread((ThreadStart)delegate
   {
      ManageDownload();
   });
   connectionManager.SetApartmentState(ApartmentState.STA);
   connectionManager.IsBackground = true;
   connectionManager.Start();
}

下载管理器线程这样做:
private void ThreadStartingPoint()
{
    downloadDetails singleDownload = new downloadDetails();
    while (downloadList.TryDequeue(out singleDownload))
    {
        downloadSemaphore.WaitOne();
        Thread singleDownloadThread = new Thread((ThreadStart)delegate
        {
            myDownloadClass.Download(singleDownload);
        });
        singleDownloadThread.SetApartmentState(ApartmentState.STA);
        singleDownloadThread.IsBackground = false;
        singleDownloadThread.Start();
    }
}

完成下载(或取消,或出错)后,单线程执行 downloadSemaphore.Release();
问题是 myDownloadClass.Download 快速开始 2 次或更多下载时看起来多次获得相同的参数

我必须使用委托(delegate),因为单个下载线程需要更新主线程上的 UI

我该如何解决这个问题?谢谢 :)

最佳答案

这个片段

while (downloadList.TryDequeue(out singleDownload))
{
    downloadSemaphore.WaitOne();
    Thread singleDownloadThread = new Thread((ThreadStart)delegate
    {
        myDownloadClass.Download(singleDownload);
    });

    ...
}

capturing the loop-variable .

修复:
while (downloadList.TryDequeue(out singleDownload))
{
    string localCopy = singleDownload;
    downloadSemaphore.WaitOne();
    Thread singleDownloadThread = new Thread((ThreadStart)delegate
    {
        myDownloadClass.Download(localCopy);
    });

    ...
}

作为更一般的建议,我会使用 Task s,也许是 Parallel类来构建一个下载管理器。

关于c# - 在 C# 中使用多线程的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20703100/

相关文章:

c# - 如何缓慢平滑地向相反方向旋转角色?

c# - 如何绑定(bind)TabControl?

c# - WPF MVVM 中与 TAP 的异步(async/await)

python - Multiprocessing.Manager() 全局变量的奇怪行为

java - 我的 ThreadLocal 始终包含并返回 null

c# - 取消后不再显示unity Game Center登录对话框

c# - Caliburn.Micro - ShowDialog() 如何关闭对话框?

c# - 读取excel表的问题

wpf - 将用户控件扩展到完整的窗口大小

从创建它的线程以外的线程访问 vb.net