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

时间:2013-12-20 11:54:09

标签: 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次或更多下载时获得多次相同的参数

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

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

1 个答案:

答案 0 :(得分:3)

这个片段

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

    ...
}

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