Solved

c# Tasks - How to wait for events

Posted on 2014-10-29
4
2,781 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
4 Comments
 
LVL 25

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 25

Expert Comment

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

autoEvent.Set();
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

This article shows how to deploy dynamic backgrounds to computers depending on the aspect ratio of display
The article shows the basic steps of integrating an HTML theme template into an ASP.NET MVC project
In this video we outline the Physical Segments view of NetCrunch network monitor. By following this brief how-to video, you will be able to learn how NetCrunch visualizes your network, how granular is the information collected, as well as where to f…
Monitoring a network: how to monitor network services and why? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the philosophy behind service monitoring and why a handshake validation is critical in network monitoring. Software utilized …

691 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