【问题标题】:Correct way to use multiple threads in C#在 C# 中使用多线程的正确方法
【发布时间】:2013-12-20 11:54:08
【问题描述】:

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

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

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

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

这里有一些我的实现的sn-ps

形式:

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 次或更多下载时看起来会多次获得相同的参数

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

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

【问题讨论】:

    标签: c# wpf multithreading synchronization


    【解决方案1】:

    这个片段

    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);
        });
    
        ...
    }
    

    作为更一般的建议,我会使用Tasks 和Parallel 类来构建下载管理器。

    【讨论】:

    • 你确定吗?调试它我总是有不同的值,因为“TryDequeue”实际上从队列中删除了值..这个循环是由一个线程完成的,所以它不能在同一时刻多次完成
    • 尝试使用 localCopy 修复。它符合看起来更多线程尝试下载同一个文件症状。
    • 试过..和..工作!谢谢 :) 但我还是不明白为什么会这样,怎么会这样?
    • 您提供给 singleDownloadThread 的匿名方法正在执行捕获。我添加了一个链接。
    猜你喜欢
    • 1970-01-01
    • 2015-06-10
    • 2015-09-29
    • 2016-03-21
    • 2022-01-23
    • 2014-01-15
    • 2013-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多