我已经编写了一个下载一些文件的方法,现在我试图让它并行下载多达5个文件,其余的则等待前面的文件完成。我为此使用了一个ManualResetEvent,但是当我包含同步部分时,它就不会再下载任何东西了(如果没有它,它就能工作)。
以下是这些方法的代码:
static readonly int maxFiles = 5;
static int files = 0;
static object filesLocker = new object();
static System.Threading.ManualResetEvent sync = new System.Threading.ManualResetEvent(true);
/// <summary>
/// Download a file from wikipedia asynchronously
/// </summary>
/// <param name="filename"></param>
public void DoanloadFileAsync(string filename)
{
...
System.Threading.ThreadPool.QueueUserWorkItem(
(o) =>
{
bool loop = true;
while (loop)
if (sync.WaitOne())
lock (filesLocker)
{
if (files < maxFiles)
{
++files;
if (files == maxFiles)
sync.Reset();
loop = false;
}
}
try
{
WebClient downloadClient = new WebClient();
downloadClient.OpenReadCompleted += new OpenReadCompletedEventHandler(downloadClient_OpenReadCompleted);
downloadClient.OpenReadAsync(new Uri(url, UriKind.Absolute));
//5 of them do get here
}
catch
{
lock (filesLocker)
{
--files;
sync.Set();
}
throw;
}
});
}
void downloadClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
try
{
//but none of the 5 get here
...Download logic... //works without the ManualResetEvent
}
finally
{
lock (filesLocker)
{
--files;
sync.Set();
}
}
}我做错了什么吗?
它是用Silverlight 4为Windows 7.编写的
编辑:在Silverlight 4.中没有信号量或SemaphoreSlim
发布于 2010-07-20 10:20:00
我在评论中的意思是,当您可以使用lock时,可以使用一个缓慢的Interlocked。而且这样会更有表现力。
最多5次并行活动下载:
public class Downloader
{
private int fileCount = 0;
private AutoResetEvent sync = new AutoResetEvent(false);
private void StartNewDownload(object o)
{
if (Interlocked.Increment(ref this.fileCount) > 5) this.sync.WaitOne();
WebClient downloadClient = new WebClient();
downloadClient.OpenReadCompleted += downloadClient_OpenReadCompleted;
downloadClient.OpenReadAsync(new Uri(o.ToString(), UriKind.Absolute));
}
private void downloadClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
try
{
// Download logic goes here.
}
catch {}
finally
{
this.sync.Set();
Interlocked.Decrement(ref this.fileCount);
}
}
public void Run()
{
string o = "url1";
System.Threading.ThreadPool.QueueUserWorkItem(this.StartNewDownload, o);
Thread.Sleep(100);
o = "url2";
System.Threading.ThreadPool.QueueUserWorkItem(this.StartNewDownload, o);
o = "url3";
System.Threading.ThreadPool.QueueUserWorkItem(this.StartNewDownload, o);
Thread.Sleep(200);
o = "url4";
System.Threading.ThreadPool.QueueUserWorkItem(this.StartNewDownload, o);
o = "url5";
System.Threading.ThreadPool.QueueUserWorkItem(this.StartNewDownload, o);
o = "url6";
System.Threading.ThreadPool.QueueUserWorkItem(this.StartNewDownload, o);
o = "url7";
System.Threading.ThreadPool.QueueUserWorkItem(this.StartNewDownload, o);
Thread.Sleep(200);
o = "url8";
System.Threading.ThreadPool.QueueUserWorkItem(this.StartNewDownload, o);
Thread.Sleep(400);
}
}发布于 2010-07-20 09:04:40
似乎您正在尝试限制可以同时进入关键部分(文件下载)的线程数量。而不是试图手工制作这个,使用一个System.Threading.Semaphore -这就是它的作用!
发布于 2010-07-20 09:03:55
从外观上看,WaitOne()在创建WebClient之前就被击中了。由于调用Set()的所有代码都在事件处理程序或异常处理程序中,所以它永远不会命中。
可能您错误地将WebClient代码包含在线程池线程方法中,而该方法应该在线程池线程方法之外。
System.Threading.ThreadPool.QueueUserWorkItem(
(o) =>
{
bool loop = true;
while (loop)
if (sync.WaitOne())
lock (filesLocker)
{
if (files < maxFiles)
{
++files;
if (files == maxFiles)
sync.Reset();
loop = false;
}
}
});
//Have the try catch OUTSIDE the background thread.
try
{
WebClient downloadClient = new WebClient();
downloadClient.OpenReadCompleted += new OpenReadCompletedEventHandler(downloadClient_OpenReadCompleted);
downloadClient.OpenReadAsync(new Uri(url, UriKind.Absolute));
//5 of them do get here
}
catch
{
lock (filesLocker)
{
--files;
sync.Set();
}
throw;
}https://stackoverflow.com/questions/3288307
复制相似问题