首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AutoResetEvent使用问题

AutoResetEvent使用问题
EN

Stack Overflow用户
提问于 2013-07-12 20:02:45
回答 3查看 1.2K关注 0票数 0

我试图使用一个AutoResetEvent对象来阻止线程,直到异步。WebClient的下载已经完成。

我的问题是,一旦调用WaitOne(),线程就会锁定在那里,VS永远不会到达DownloadComplete事件处理程序方法中的断点。

这是我的密码

代码语言:javascript
复制
//Class used to pass arguments to WebClient's events...

public class RunArgs
{
    public JobInfo jobInfo;
    public int jobTotal;
    public int jobIndex;
    public AutoResetEvent AutoResetEventObject;
}

List<JobInfo> jl = ConfigSectionWrapper.GetAllJobs();

int jobAmount = jl.Count;
int jobIndex = 0;

RunArgs args = new RunArgs();
args.jobTotal = jl.Count;


foreach (JobInfo ji in jl)
{


    if (ji.enabled == "0")
    {
        args.jobIndex++;
        continue;
    }

    try
    {
        args.jobIndex++;
        args.jobInfo = ji;

        appLog.Source = ji.eventSource;
        appLog.WriteEntry(string.Format("Started job {0}...", ji.jobName),         EventLogEntryType.Information);
        ji.fullFileName = string.Format(ji.reportFileName, string.Format("{0}-{1}-{2}", DateTime.Now.Year.ToString(), DateTime.Now.Month.ToString().PadLeft(2, '0'), DateTime.Now.Day.ToString().PadLeft(2, '0')));
        ji.fullFileName = string.Format("{0}{1}", ji.downloadDirectory, ji.fullFileName);

        using (WebClient wc = new WebClient())
        {
            AutoResetEvent notifier = new AutoResetEvent(false);
            args.AutoResetEventObject = notifier;
            wc.Credentials = CredentialCache.DefaultNetworkCredentials;
            wc.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompleted);
            wc.DownloadFileAsync(new Uri(args.jobInfo.reportURL), args.jobInfo.fullFileName, args); //Pass the args params to event handler...
            notifier.WaitOne();
         }
    }
    catch (Exception ex)
    {
        appLog.WriteEntry(string.Format("Error starting report execution: {0}", ex.Message), EventLogEntryType.Error);
        DeleteFile(ji.fullFileName);
    }

}

private void DownloadCompleted(object sender, AsyncCompletedEventArgs e)
{

    RunArgs args = (RunArgs)e.UserState;

    //Do things....

    args.AutoResetEventObject.Set();  
 }

因此,我在构造函数中实例化了通知程序,因为我不希望它的状态已经发出信号。除非我看错了MSDN?

有什么明显的问题吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-07-15 14:33:29

以下是我最后所做的:

代码语言:javascript
复制
private AutoResetEvent notifier = new AutoResetEvent(false);

现在,主循环看起来如下:

代码语言:javascript
复制
        foreach (JobInfo ji in jl)
        {
            if (ji.enabled == "0")
            {
                args.jobIndex++;
                continue;
            }

            args.jobInfo = ji;
            Thread t = new Thread(new ParameterizedThreadStart(startDownload));
            t.Start(args);
            notifier.WaitOne();
        }

private void startDownload(object startArgs)
    {
        RunArgs args = (RunArgs)startArgs;

        try
        {
            args.jobIndex++;
            appLog.Source = args.jobInfo.eventSource;
            appLog.WriteEntry(string.Format("Started job {0}...", args.jobInfo.jobName), EventLogEntryType.Information);
            args.jobInfo.fullFileName = string.Format(args.jobInfo.reportFileName, string.Format("{0}-{1}-{2}", DateTime.Now.Year.ToString(), DateTime.Now.Month.ToString().PadLeft(2, '0'), DateTime.Now.Day.ToString().PadLeft(2, '0')));
            args.jobInfo.fullFileName = string.Format("{0}{1}", args.jobInfo.downloadDirectory, args.jobInfo.fullFileName);

            WebClient wc = new WebClient();

            wc.Credentials = CredentialCache.DefaultNetworkCredentials;
            wc.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompleted);
            wc.DownloadFileAsync(new Uri(args.jobInfo.reportURL), args.jobInfo.fullFileName, args); //Pass the args params to event handler...

        }
        catch (Exception ex)
        {
            appLog.WriteEntry(string.Format("Error starting report execution: {0}", ex.Message), EventLogEntryType.Error);
            DeleteFile(args.jobInfo.fullFileName);
            notifier.Set();
        }

    }

因此,现在DownloadFileCompleteEvent.正在阻塞主线程,但是t可以成功地触发该在DownloadFileCompleted事件中,我显然也在做一个notifier.Set()。

谢谢大家!

票数 0
EN

Stack Overflow用户

发布于 2013-07-12 20:54:50

WebClient使用AsyncOperationManager来管理异步操作。因此,请确保您知道这些异步操作是如何在不同场景下调用的。

在WinForms下

WinForm应用程序中,AsyncOperationManager使用WindowsFormsSynchronizationContext。正如@Michael所说,WaitOne()调用阻止主表单线程触发DownloadCompleted事件。在WinForms中,DownloadCompleted在主WinForm线程上执行。

因此,删除notifier.WaitOne(),它应该可以工作。DownloadCompleted需要由主窗口线程调用(大概是您正在用WaitOne()阻塞的线程)。

控制台下的应用程序

Console类型的应用程序中,AsyncOperationManager使用System.Threading.SynchronizationContextDownloadCompleted由线程组成线程池异步执行。

在一个notifier.WaitOne()应用程序下调用Console没有问题;上面的代码就像预期的那样工作。

票数 2
EN

Stack Overflow用户

发布于 2013-07-12 20:14:06

我还没有找到任何文档来支持这一点,但是查看Reflector中的WebClient代码,事件似乎是在主线程上引发的,而不是在后台线程中引发的。由于主线程在调用notifier.WaitOne()时是阻塞的,所以事件处理程序永远不会被调用。

如果您提供的示例准确地表示了您的代码,那么绝对没有必要使用wc.DownloadFileAsync()而不是wc.DownloadFile()notifier.WaitOne()调用最终使其成为同步操作。如果您正在寻找真正的异步操作,则必须以不同的方式执行此操作。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17623113

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档