Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.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# 与ManualResetEvent同步时出现问题_C#_Synchronization_Silverlight 4.0_Windows Phone 7 - Fatal编程技术网

C# 与ManualResetEvent同步时出现问题

C# 与ManualResetEvent同步时出现问题,c#,synchronization,silverlight-4.0,windows-phone-7,C#,Synchronization,Silverlight 4.0,Windows Phone 7,我已经编写了一个方法来下载一些文件,现在我正试图让它并行下载多达5个文件,其余的等待前面的文件完成。 我正在为此使用ManualResetEvent,但当我包含同步部分时,它不再下载任何内容(没有它,它就可以工作) 以下是这些方法的代码: static readonly int maxFiles = 5; static int files = 0; static object filesLocker = new object(); static System.Th

我已经编写了一个方法来下载一些文件,现在我正试图让它并行下载多达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();
            }
        }
    }
static readonly int maxFiles=5;
静态int文件=0;
静态对象filesLocker=新对象();
静态System.Threading.ManualResetEvent sync=新的System.Threading.ManualResetEvent(真);
/// 
///从wikipedia异步下载文件
/// 
/// 
public void DoanloadFileAsync(字符串文件名)
{
...
System.Threading.ThreadPool.QueueUserWorkItem(
(o) =>
{
布尔循环=真;
while(循环)
if(sync.WaitOne())
锁(文件锁)
{
if(文件
我做错什么了吗

它是用适用于Windows Phone 7的Silverlight 4编写的。


编辑:Silverlight 4中没有信号灯或信号灯LIM。

从外观上看,在创建
网络客户端之前,
WaitOne()
被点击。由于调用
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;
            }
System.Threading.ThreadPool.QueueUserWorkItem(
(o) =>
{
布尔循环=真;
while(循环)
if(sync.WaitOne())
锁(文件锁)
{
if(文件
您似乎试图限制可以立即进入关键部分(文件下载)的线程数量。与其尝试手工制作,不如使用
系统.Threading.Semaphore
——它就是这么做的

我在评论中的意思是,当您可以使用
联锁时,使用慢速
锁。而且这样做会更有效

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

当您可以使用
System.Threading.interlocated.Decrement()方法等时,为什么要锁定?因为我也想调用sync.Set(),我想有人从另一个线程冷调用sync.Set(),然后我递减,一些线程递增并调用sync.Reset(),然后我调用sync.Set()我得到了更多的maxFiles线程下载。检查我的答案,这就是你要找的。另外,使用重置事件也可以,我只是不认为需要锁。哦,我使用AutoResteEvent,因为它正是您在这里需要的;对于当前的DownloadAsync调用。这样它一次只下载maxfile,其余的等待前面的一次下载完成。(我在调试时没有收到该部分的NullReferenceException,所以我猜它是正确创建的)。Silverlight for Windows Phone中似乎没有信号灯。还有什么类似于信号灯的东西我可以用吗?啊-是的-对不起-也许没有。我正在查看完整框架的文档。我在这里找到了一些有用的链接,人们可以在Silverlight中讨论替代方案:Rob是正确的;您使用了错误的同步原语。如果您使用的是.NET 4.0,请改用
System.Threading.SemaphoreSlim
——它轻量级、快速,并且支持取消令牌,在执行长时间运行的操作时,您可能会发现这一功能很有用