Search code examples
c#.netmultithreadingautoresetevent

AutoResetEvent use issue


I'm trying to use an AutoResetEvent object to block the thread until the async. download of a WebClient is done.

My problem is that once I call WaitOne(), the thread just locks there and VS never reaches the breakpoint in the DownloadComplete event handler method.

Here's my code

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

So I instantiate notifier with false in the constructor, because I don't want its status to be signaled already. Unless I'm reading MSDN wrong ?

Anything obviously wrong ?


Solution

  • Here's what I ended up doing:

    private AutoResetEvent notifier = new AutoResetEvent(false);
    

    Now the main loop looks like:

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

    So now the AutoResetEvent is blocking the main thread but t can successfully trigger the DownloadFileCompleteEvent. And in the DownloadFileCompleted event, I'm obviously doing a notifier.Set() too.

    Thanks all!