Solved

c# Tasks - How to wait for events

Posted on 2014-10-29
4
1,977 Views
Last Modified: 2014-12-15
Hi,

I have some code which initiates a download. This results in one of the following async events being triggered. I need the application to wait for one of these events before continuing.

Is this a job for tasks? Can I create a task with my download code which returns 'task complete' when one of the 3 events below fire?

(stdFile_.saver as _IStreamCollectorEvents_Event).stopped += (collector) =>
{
	Console.WriteLine("Download stopped");
};
(stdFile_.saver as _IStreamCollectorEvents_Event).failed += (sender, error) =>
{
	Console.WriteLine("Download failed");
};
(video as _IStream_Events_Event).stopped += (s) =>
{
	Console.WriteLine("Download Complete!");
};

Open in new window

0
Comment
Question by:mhdi
  • 2
4 Comments
 
LVL 24

Accepted Solution

by:
chaau earned 250 total points
ID: 40412359
You can use a WaitHandle class. Register it before the download starts. Then just use the WaitOne() method in the main program. I recommend you use the version of the method where you can specify the timeout to make sure your program does not forever. The pseudo code will be similar to this:

Create a global variable:
static AutoResetEvent autoEvent = new AutoResetEvent(false);

Open in new window

Then in your main program start your download and wait:
       Console.WriteLine("Main starting.");

        // your code for asynchronous download here. 

        // Wait for work method to signal. 
        if(autoEvent.WaitOne(1000))
        {
            Console.WriteLine("download event signaled.");
        }
        else
        {
            Console.WriteLine("Timed out waiting for download");
        }
        Console.WriteLine("Main ending.");

Open in new window

And your evens all do the same:
(stdFile_.saver as _IStreamCollectorEvents_Event).stopped += (collector) =>
{
	Console.WriteLine("Download stopped");
	autoEvent.Set();
};
(stdFile_.saver as _IStreamCollectorEvents_Event).failed += (sender, error) =>
{
	Console.WriteLine("Download failed");
	autoEvent.Set();
};
(video as _IStream_Events_Event).stopped += (s) =>
{
	Console.WriteLine("Download Complete!");
	autoEvent.Set();
};
                                  

Open in new window

You may also wish to introduce a global string variable for status to indicate the result of your download
0
 
LVL 14

Assisted Solution

by:Vel Eous
Vel Eous earned 250 total points
ID: 40412735
Ideally you do not want to block whilst the operation is in progress, so making use of the TPL is a viable option (there is also the older and still valid BackgroundWorker class).

The following example should get you most of the way to what you are looking for:

namespace EE.Q_28547351.ConsoleApp
{
    using System;
    using System.Threading;
    using System.Threading.Tasks;

    internal class Program
    {
        private static CancellationTokenSource cts;

        private static void Main(string[] args)
        {
            // Create a new CancellationTokenSource so that the task can be cancelled if required
            cts = new CancellationTokenSource();
            // Start the operation
            var task =
                Task.Run(() => DownloadOperation(new Progress<ProgressReport>(ReportProgress)), cts.Token)
                    .ContinueWith(TaskComplete);

            Console.WriteLine("Task running ...");
            Console.WriteLine("Press any key to cancel the process");
            Console.ReadKey();

            // Cancel the task
            cts.Cancel();

            Console.ReadKey();
        }

        // Download operation simulates where you would perform your long running process
        // This is where you will perform your download
        // I have added a delay to simulate a long running download
        private static async Task<bool> DownloadOperation(IProgress<ProgressReport> progress)
        {
            const int totalAmount = 10;
            for (var i = 1; i <= totalAmount; i++)
            {
                if (cts.IsCancellationRequested)
                {
                    return false;
                }
                await Task.Delay(1000);
                progress.Report(new ProgressReport
                {
                    CurrentProgressAmount = i,
                    TotalProgressAmount = totalAmount,
                    Message = i == totalAmount ? "All done" : "More to do"
                });
            }

            return true;
        }

        private static void ReportProgress(ProgressReport report)
        {
            Console.WriteLine(report);
        }

        private static void TaskComplete(Task<bool> task)
        {
            // Do something when the task completes
            Console.WriteLine(task.Result);
        }
    }

    // Encapsulates progress information and is used by the IProgress<T> interface
    internal class ProgressReport
    {
        public int CurrentProgressAmount { get; set; }
        public int TotalProgressAmount { get; set; }
        public string Message { get; set; }

        public override string ToString()
        {
            return string.Format("Processing {0} of {1}. {2}", this.CurrentProgressAmount, this.TotalProgressAmount,
                this.Message);
        }
    }
}

Open in new window

0
 

Author Comment

by:mhdi
ID: 40423311
Apologies for the late reply guys.

@chaau - I need the ability to signal the main thread whether the download completed successfully or not. Can I do this with the "AutoResetEvent"?  Or do I keep a separate variable which holds the download status. eg "bool downloadComplete = false" which gets changed to "true" when the download complete event is fired.

@Tchuki - I like your proposed solution, but how do I tie in the events mentioned in my top post?
0
 
LVL 24

Expert Comment

by:chaau
ID: 40423359
You just need the AutoResetEvent, and set it

autoEvent.Set();
0

Featured Post

Master Your Team's Linux and Cloud Stack

Come see why top tech companies like Mailchimp and Media Temple use Linux Academy to build their employee training programs.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

This document covers how to connect to SQL Server and browse its contents.  It is meant for those new to Visual Studio and/or working with Microsoft SQL Server.  It is not a guide to building SQL Server database connections in your code.  This is mo…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question