How to handle Exceptions in System.Threading.Timer - c#

I'm trying to handle exception but it doesn't work!
whats the problem?
lets say in Main i run SetUpTimer with any parameters.
private void SetUpTimer(TimeSpan alertTime, string name)
{
DateTime current = DateTime.Now;
TimeSpan timeToGo = alertTime - current.TimeOfDay;
try
{
Timer timer = new Timer(x => RunReportTask(name),null, timeToGo, Timeout.InfiniteTimeSpan));
catch(Exception e)
{
Console.WriteLine("Log Exception....")
}
}
private void RunReportTask(string name)
{
Console.WriteLine("\r\n\r\nSTART Task \t\tReport: " + name);
//DELAY 25 sec
Task.Delay(25000);
if (name.Equals("Report A") || name.Equals("Report D") || name.Equals("Report F"))
{
throw new Exception("Task failed!!!");
}
else
{
Console.WriteLine("Task: \t\t" + name + "\tDONE.");
}
}
so now if i execute it will throw an exception with Report name A,D,F. but it won't catch it, but why? and what can i do about it?

The Timer calls the TimerCallback on a separate ThreadPool thread.
Exceptions thrown in a TimerCallback method are not propagated to the code/thread where the timer was created (they just 'disapppear').
If you want to handle them outside of your callback method: you should catch them in the callback method and use some mechanism to rethrow or handle them in the original thread.
Personally I like the IProgress for this.
There are a number of syntax errors in your original code, but based on that the following example should work:
private Timer timer;
public void SetUpTimer(DateTime alertTime, string name)
{
var progress = new Progress<Exception>((e) =>
{
// handle exception form timercallback here, or just rethrow it...
throw e;
});
DateTime current = DateTime.Now;
TimeSpan timeToGo = (alertTime - current);
timer = new Timer(x => RunReportTask(name, progress),
null, timeToGo, Timeout.InfiniteTimeSpan);
}
private void RunReportTask(string name, IProgress<Exception> progress)
{
try
{
Console.WriteLine("\r\n\r\nSTART Task \t\tReport: " + name);
//DELAY 25 sec
Task.Delay(25000);
if(name.Equals("Report A") || name.Equals("Report D") || name.Equals("Report F"))
{
throw new Exception("Task failed!!!");
}
else
{
Console.WriteLine("Task: \t\t" + name + "\tDONE.");
}
}
catch(Exception e)
{
progress.Report(e);
}
}
Warning: Apart from the syntax, there is an important issue with the code in your example. You have to keep a reference to your Timer instance for as long as you want to have it active. Whenever a Timer goes out of scope, it becomes a candidate for garbage collection.
In your example the Timeris a local variable which goes out of scope as soon as the method finishes. If it is garbage collected before alertTime, the TimerCallback will never be called. For that reason i have promoted your Timerto a private field of your class.
Furthermore, when you no longer need the Timer, you should call Dispose() on the Timer to release its resources (e.g. in a Dispose methode for your class).

Try this one (because you did not close brackets in try block):
private void SetUpTimer(TimeSpan alertTime, string name)
{
DateTime current = DateTime.Now;
TimeSpan timeToGo = alertTime - current.TimeOfDay;
try
{
Timer timer = new Timer(x => RunReportTask(name),null, timeToGo, Timeout.InfiniteTimeSpan));
}
catch(Exception e)
{
Console.WriteLine("Log Exception....")
}
}

Related

How to return result from delegate that performing in thread? [duplicate]

How do I return a value from a thread?
One of the easiest ways to get a return value from a thread is to use closures. Create a variable that will hold the return value from the thread and then capture it in a lambda expression. Assign the "return" value to this variable from the worker thread and then once that thread ends you can use it from the parent thread.
void Main()
{
object value = null; // Used to store the return value
var thread = new Thread(
() =>
{
value = "Hello World"; // Publish the return value
});
thread.Start();
thread.Join();
Console.WriteLine(value); // Use the return value here
}
It depends on how do you want to create the thread and available .NET version:
.NET 2.0+:
A) You can create the Thread object directly. In this case you could use "closure" - declare variable and capture it using lambda-expression:
object result = null;
Thread thread = new System.Threading.Thread(() => {
//Some work...
result = 42; });
thread.Start();
thread.Join();
Console.WriteLine(result);
B) You can use delegates and IAsyncResult and return value from EndInvoke() method:
delegate object MyFunc();
...
MyFunc x = new MyFunc(() => {
//Some work...
return 42; });
IAsyncResult asyncResult = x.BeginInvoke(null, null);
object result = x.EndInvoke(asyncResult);
C) You can use BackgroundWorker class. In this case you could use captured variable (like with Thread object) or handle RunWorkerCompleted event:
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (s, e) => {
//Some work...
e.Result = 42;
};
worker.RunWorkerCompleted += (s, e) => {
//e.Result "returned" from thread
Console.WriteLine(e.Result);
};
worker.RunWorkerAsync();
.NET 4.0+:
Starting with .NET 4.0 you could use Task Parallel Library and Task class to start your threads. Generic class Task<TResult> allows you to get return value from Result property:
//Main thread will be blocked until task thread finishes
//(because of obtaining the value of the Result property)
int result = Task.Factory.StartNew(() => {
//Some work...
return 42;}).Result;
.NET 4.5+:
Starting with .NET 4.5 you could also use async/await keywords to return value from task directly instead of obtaining Result property:
int result = await Task.Run(() => {
//Some work...
return 42; });
Note: method, which contains the code above shoud be marked with asynckeyword.
For many reasons using of Task Parallel Library is preferable way of working with threads.
I would use the BackgroundWorker approach and return the result in e.Result.
EDIT:
This is commonly associated with WinForms and WPF, but can be used by any type of .NET application. Here's sample code for a console app that uses BackgroundWorker:
using System;
using System.Threading;
using System.ComponentModel;
using System.Collections.Generic;
using System.Text;
namespace BGWorker
{
class Program
{
static bool done = false;
static void Main(string[] args)
{
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += new DoWorkEventHandler(bg_DoWork);
bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);
bg.RunWorkerAsync();
while (!done)
{
Console.WriteLine("Waiting in Main, tid " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(100);
}
}
static void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("Completed, tid " + Thread.CurrentThread.ManagedThreadId);
done = true;
}
static void bg_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 5; i++)
{
Console.WriteLine("Work Line: " + i + ", tid " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(500);
}
}
}
}
Output:
Waiting in Main, tid 10
Work Line: 1, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 2, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 3, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 4, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 5, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Completed, tid 6
2014 UPDATE
See #Roger's answer below.
https://stackoverflow.com/a/24916747/141172
He points out that you can use a Task that returns a Task<T>, and check Task<T>.Result.
A thread isn't a method - you don't normally "return" a value.
However, if you're trying to fetch a value back from the results of some processing, you have many options, the two main ones being:
You can synchronize a shared piece of data, and set it appropriately.
You can also pass the data back in some form of callback.
It really depends on how you're creating the thread, and how you want to use it, as well as the language/framework/tools you're using.
Simply use the delegate approach.
int val;
Thread thread = new Thread(() => { val = Multiply(1, 2); });
thread.Start();
Now make Multiply function that will work on another thread:
int Multiply(int x, int y)
{
return x * y;
}
My favorite class, runs any method on another thread with just 2 lines of code.
class ThreadedExecuter<T> where T : class
{
public delegate void CallBackDelegate(T returnValue);
public delegate T MethodDelegate();
private CallBackDelegate callback;
private MethodDelegate method;
private Thread t;
public ThreadedExecuter(MethodDelegate method, CallBackDelegate callback)
{
this.method = method;
this.callback = callback;
t = new Thread(this.Process);
}
public void Start()
{
t.Start();
}
public void Abort()
{
t.Abort();
callback(null); //can be left out depending on your needs
}
private void Process()
{
T stuffReturned = method();
callback(stuffReturned);
}
}
usage
void startthework()
{
ThreadedExecuter<string> executer = new ThreadedExecuter<string>(someLongFunction, longFunctionComplete);
executer.Start();
}
string someLongFunction()
{
while(!workComplete)
WorkWork();
return resultOfWork;
}
void longFunctionComplete(string s)
{
PrintWorkComplete(s);
}
Beware that longFunctionComplete will NOT execute on the same thread as starthework.
For methods that take parameters you can always use closures, or expand the class.
Here is a simple example using a delegate ...
void Main()
{
DoIt d1 = Doer.DoThatThang;
DoIt d2 = Doer.DoThatThang;
IAsyncResult r1 = d1.BeginInvoke( 5, null, null );
IAsyncResult r2 = d2.BeginInvoke( 10, null, null );
Thread.Sleep( 1000 );
var s1 = d1.EndInvoke( r1 );
var s2 = d2.EndInvoke( r2 );
s1.Dump(); // You told me 5
s2.Dump(); // You told me 10
}
public delegate string DoIt( int x );
public class Doer
{
public static string DoThatThang( int x )
{
return "You told me " + x.ToString();
}
}
There's a terrific series on threading at Threading in C#.
With the latest .NET Framework, it is possible to return a value from a separate thread using a Task, where the Result property blocks the calling thread until the task finishes:
Task<MyClass> task = Task<MyClass>.Factory.StartNew(() =>
{
string s = "my message";
double d = 3.14159;
return new MyClass { Name = s, Number = d };
});
MyClass test = task.Result;
For details, please see http://msdn.microsoft.com/en-us/library/dd537613(v=vs.110).aspx
ThreadStart delegates in C# used to start threads have return type 'void'.
If you wish to get a 'return value' from a thread, you should write to a shared location (in an appropriate thread-safe manner) and read from that when the thread has completed executing.
I came across this thread when also trying to obtain the return value of a method that gets executed within a Thread. I thought I would post my solution that works.
This solution uses an class to store both the method to be executed (indirectly) and stores the returning value. The class can be used for any function and any return type. You just instantiate the object using the return value type and then pass the function to call via a lambda (or delegate).
C# 3.0 Implementation
public class ThreadedMethod<T>
{
private T mResult;
public T Result
{
get { return mResult; }
private set { mResult = value; }
}
public ThreadedMethod()
{
}
//If supporting .net 3.5
public void ExecuteMethod(Func<T> func)
{
Result = func.Invoke();
}
//If supporting only 2.0 use this and
//comment out the other overload
public void ExecuteMethod(Delegate d)
{
Result = (T)d.DynamicInvoke();
}
}
To use this code you can use a Lambda (or a delegate). Here is the example using lambdas:
ThreadedMethod<bool> threadedMethod = new ThreadedMethod<bool>();
Thread workerThread = new Thread((unused) =>
threadedMethod.ExecuteMethod(() =>
SomeMethod()));
workerThread.Start();
workerThread.Join();
if (threadedMethod.Result == false)
{
//do something about it...
}
VB.NET 2008 Implementation
Anyone using VB.NET 2008 can't use lambdas with non-value returning methods. This affects the ThreadedMethod class, so we'll make ExecuteMethod return the value of the function. This doesn't hurt anything.
Public Class ThreadedMethod(Of T)
Private mResult As T
Public Property Result() As T
Get
Return mResult
End Get
Private Set(ByVal value As T)
mResult = value
End Set
End Property
Sub New()
End Sub
'If supporting .net 3.5'
Function ExecuteMethod(ByVal func As Func(Of T)) As T
Result = func.Invoke()
Return Result
End Function
'If supporting only 2.0 use this and'
'comment out the other overload'
Function ExecuteMethod(ByVal d As [Delegate]) As T
Result = DirectCast(d.DynamicInvoke(), T)
Return Result
End Function
End Class
If you don't want to use a BackgroundWorker, and just use a regular Thread, then you can fire an event to return data like this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace ThreadWithDataReturnExample
{
public partial class Form1 : Form
{
private Thread thread1 = null;
public Form1()
{
InitializeComponent();
thread1 = new Thread(new ThreadStart(this.threadEntryPoint));
Thread1Completed += new AsyncCompletedEventHandler(thread1_Thread1Completed);
}
private void startButton_Click(object sender, EventArgs e)
{
thread1.Start();
//Alternatively, you could pass some object
//in such as Start(someObject);
//With apprioriate locking, or protocol where
//no other threads access the object until
//an event signals when the thread is complete,
//any other class with a reference to the object
//would be able to access that data.
//But instead, I'm going to use AsyncCompletedEventArgs
//in an event that signals completion
}
void thread1_Thread1Completed(object sender, AsyncCompletedEventArgs e)
{
if (this.InvokeRequired)
{//marshal the call if we are not on the GUI thread
BeginInvoke(new AsyncCompletedEventHandler(thread1_Thread1Completed),
new object[] { sender, e });
}
else
{
//display error if error occurred
//if no error occurred, process data
if (e.Error == null)
{//then success
MessageBox.Show("Worker thread completed successfully");
DataYouWantToReturn someData = e.UserState as DataYouWantToReturn;
MessageBox.Show("Your data my lord: " + someData.someProperty);
}
else//error
{
MessageBox.Show("The following error occurred:" + Environment.NewLine + e.Error.ToString());
}
}
}
#region I would actually move all of this into it's own class
private void threadEntryPoint()
{
//do a bunch of stuff
//when you are done:
//initialize object with data that you want to return
DataYouWantToReturn dataYouWantToReturn = new DataYouWantToReturn();
dataYouWantToReturn.someProperty = "more data";
//signal completion by firing an event
OnThread1Completed(new AsyncCompletedEventArgs(null, false, dataYouWantToReturn));
}
/// <summary>
/// Occurs when processing has finished or an error occurred.
/// </summary>
public event AsyncCompletedEventHandler Thread1Completed;
protected virtual void OnThread1Completed(AsyncCompletedEventArgs e)
{
//copy locally
AsyncCompletedEventHandler handler = Thread1Completed;
if (handler != null)
{
handler(this, e);
}
}
#endregion
}
}
Can use This Code:
private Object MyThread(Object Data)
{
Object response = null;
Thread newThread = new Thread(() =>
{
response = MyFunction(Data);
//MyFunction Is Function that you Define
});
newThread.Start();
newThread.Join();
return response;
}
The BackgroundWorker is nice when developing for Windows Forms.
Say you wanted to pass a simple class back and forth:
class Anything {
// Number and Text are for instructional purposes only
public int Number { get; set; }
public string Text { get; set; }
// Data can be any object - even another class
public object Data { get; set; }
}
I wrote up a short class that does the following:
Create or Clear a list
Start a loop
In loop, create a new item for the list
In loop, create a thread
In loop, send the item as a parameter to the thread
In loop, start the thread
In loop, add thread to list to watch
After loop, join each thread
After all joins have completed, display the results
From inside the thread routine:
Call lock so that only 1 thread can enter this routine at a time (others have to wait)
Post information about the item.
Modify the item.
When the thread completes, the data is displayed on the console.
Adding a delegate can be useful for posting your data directly back to your main thread, but you may need to use Invoke if some of the data items are not thread safe.
class AnyTask {
private object m_lock;
public AnyTask() {
m_lock = new object();
}
// Something to use the delegate
public event MainDelegate OnUpdate;
public void Test_Function(int count) {
var list = new List<Thread>(count);
for (var i = 0; i < count; i++) {
var thread = new Thread(new ParameterizedThreadStart(Thread_Task));
var item = new Anything() {
Number = i,
Text = String.Format("Test_Function #{0}", i)
};
thread.Start(item);
list.Add(thread);
}
foreach (var thread in list) {
thread.Join();
}
}
private void MainUpdate(Anything item, bool original) {
if (OnUpdate != null) {
OnUpdate(item, original);
}
}
private void Thread_Task(object parameter) {
lock (m_lock) {
var item = (Anything)parameter;
MainUpdate(item, true);
item.Text = String.Format("{0}; Thread_Task #{1}", item.Text, item.Number);
item.Number = 0;
MainUpdate(item, false);
}
}
}
To test this, create a little Console Application, and put this in the Program.cs file:
// A delegate makes life simpler
delegate void MainDelegate(Anything sender, bool original);
class Program {
private const int COUNT = 15;
private static List<Anything> m_list;
static void Main(string[] args) {
m_list = new List<Anything>(COUNT);
var obj = new AnyTask();
obj.OnUpdate += new MainDelegate(ThreadMessages);
obj.Test_Function(COUNT);
Console.WriteLine();
foreach (var item in m_list) {
Console.WriteLine("[Complete]:" + item.Text);
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
private static void ThreadMessages(Anything item, bool original) {
if (original) {
Console.WriteLine("[main method]:" + item.Text);
} else {
m_list.Add(item);
}
}
}
Here is a screenshot of what I got with this:
I hope others can understand what I've tried to explain.
I enjoy working on threads and using delegates. They make C# a lot of fun.
Appendix: For VB Coders
I wanted to see what was involved in writing the code above as a VB Console Application. The conversion involved a few things I didn't expect, so I will update this thread here for those wanting to know how to thread in VB.
Imports System.Threading
Delegate Sub MainDelegate(sender As Anything, original As Boolean)
Class Main
Private Const COUNT As Integer = 15
Private Shared m_list As List(Of Anything)
Public Shared Sub Main(args As String())
m_list = New List(Of Anything)(COUNT)
Dim obj As New AnyTask()
AddHandler obj.OnUpdate, New MainDelegate(AddressOf ThreadMessages)
obj.Test_Function(COUNT)
Console.WriteLine()
For Each item As Anything In m_list
Console.WriteLine("[Complete]:" + item.Text)
Next
Console.WriteLine("Press any key to exit.")
Console.ReadKey()
End Sub
Private Shared Sub ThreadMessages(item As Anything, original As Boolean)
If original Then
Console.WriteLine("[main method]:" + item.Text)
Else
m_list.Add(item)
End If
End Sub
End Class
Class AnyTask
Private m_lock As Object
Public Sub New()
m_lock = New Object()
End Sub
' Something to use the delegate
Public Event OnUpdate As MainDelegate
Public Sub Test_Function(count As Integer)
Dim list As New List(Of Thread)(count)
For i As Int32 = 0 To count - 1
Dim thread As New Thread(New ParameterizedThreadStart(AddressOf Thread_Task))
Dim item As New Anything()
item.Number = i
item.Text = String.Format("Test_Function #{0}", i)
thread.Start(item)
list.Add(thread)
Next
For Each thread As Thread In list
thread.Join()
Next
End Sub
Private Sub MainUpdate(item As Anything, original As Boolean)
RaiseEvent OnUpdate(item, original)
End Sub
Private Sub Thread_Task(parameter As Object)
SyncLock m_lock
Dim item As Anything = DirectCast(parameter, Anything)
MainUpdate(item, True)
item.Text = [String].Format("{0}; Thread_Task #{1}", item.Text, item.Number)
item.Number = 0
MainUpdate(item, False)
End SyncLock
End Sub
End Class
Class Anything
' Number and Text are for instructional purposes only
Public Property Number() As Integer
Get
Return m_Number
End Get
Set(value As Integer)
m_Number = value
End Set
End Property
Private m_Number As Integer
Public Property Text() As String
Get
Return m_Text
End Get
Set(value As String)
m_Text = value
End Set
End Property
Private m_Text As String
' Data can be anything or another class
Public Property Data() As Object
Get
Return m_Data
End Get
Set(value As Object)
m_Data = value
End Set
End Property
Private m_Data As Object
End Class
Threads do not really have return values. However, if you create a delegate, you can invoke it asynchronously via the BeginInvoke method. This will execute the method on a thread pool thread. You can get any return value from such as call via EndInvoke.
Example:
static int GetAnswer() {
return 42;
}
...
Func<int> method = GetAnswer;
var res = method.BeginInvoke(null, null); // provide args as needed
var answer = method.EndInvoke(res);
GetAnswer will execute on a thread pool thread and when completed you can retrieve the answer via EndInvoke as shown.
class Program
{
static void Main(string[] args)
{
string returnValue = null;
new Thread(
() =>
{
returnValue =test() ;
}).Start();
Console.WriteLine(returnValue);
Console.ReadKey();
}
public static string test()
{
return "Returning From Thread called method";
}
}
A simple solution is to pass a parameter by ref to the function that is running in the thread and change its value in the thread.
// create a list of threads
List<Thread> threads = new List<Thread>();
//declare the ref params
bool is1 = false;
bool is2 = false;
threads.Add(new Thread(() => myFunction(someVar, ref is1)));
threads.Add(new Thread(() => myFunction(someVar, ref is2)));
threads.ForEach(x => x.Start());
// wait for threads to finish
threads.ForEach(x => x.Join());
//check the ref params
if (!is1)
{
//do something
}
if (!is2)
{
//do somethign else
}
If you can't change the function that is running in the tread, you can wrap it another function:
bool theirFunction(var someVar){
return false;
}
void myFunction(var someVar ref bool result){
result = theirFunction(myVar);
}
class Program
{
public static void ActionResultPrint(string i)
{
Console.WriteLine(i);
}
static void Main(string[] args)
{
var tl = new List<Thread>();
tl.Add(new Thread(() => Run(10, ActionResultPrint)));
tl.Add(new Thread(() => Run(20, ActionResultPrint)));
tl.ForEach(x => x.Start());
tl.ForEach(x => x.Join());
}
public static void Run(int j, Action<string> action)
{
string rvalue = string.Empty;
for (int i = 0; i <= j; i++)
{
Thread.Sleep(100);
rvalue = i.ToString();
Console.WriteLine(rvalue);
}
action($#"output {j}");
}
}
when threads are used , value can be passed and returned in following ways:
int value = -1;
Thread t1 = new Thread(() => { value = compute(a); });
t1.Start();
if(value!=-1)
{...}
public int compute(int[] a1)
{
//...code logic
return -1;
}
I'm no kind of expert in threading, that's why I did it like this:
I created a Settings file and
Inside the new thread:
Setting.Default.ValueToBeSaved;
Setting.Default.Save();
Then I pick up that value whenever I need it.

Running multiple timers simultaneously in C# using System.Threading

I have service that I am using to pull up reports from a network location. The requirement is that ever 5 minutes I need to pull up report 1, every 10 minutes report 2 & every 3 hours report 3,4,5. So, I created a timer inside a method on a separate worker class where I am using 5 instances of System.Threading.Timer. The reports are getting pulled but not in proper order. How can I run the timers in such a way that reports can get pulled in a specific order or use 1 timer to schedule pulling of reports in specific manner?
Here's what I have done so far:
private async void pullReports()
{
try
{
await _logger.Info($"Start Report Monitoring");
Timer timer = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 1),
null,
TimeSpan.Zero,
TimeSpan.FromMinutes(5)
);
Timer timer2 = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 2),
null,
TimeSpan.Zero,
TimeSpan.FromMinutes(10)
);
Timer timer3 = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 3),
null,
TimeSpan.Zero,
TimeSpan.FromHours(3)
);
Timer timer4 = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 4),
null,
TimeSpan.Zero,
TimeSpan.FromHours(3)
);
Timer timer5 = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 5),
null,
TimeSpan.Zero,
TimeSpan.FromHours(3)
);
}
catch (Exception ex)
{
await _logger.Error($"Start Report Monitoring exception: {ex}");
}
}
Any kind of code improvements are appreciated. I think because my method Service.ReportMonitoring() is asynchronous that is the reason that is disturbing the order of collection. But I'm not sure about that.
The code for ReportNum is as follows:
private static Task<Stream> ReportMonitoring(int repnum)
{
string _urlDataFormat = "https://{0}/cgi-bin/CGILink?cmd=vtranssetz&period=2&reptnum={1}";
string dataUrl = string.Format(_urlDataFormat, <serverIP>, repnum);
return HttpService.ExecuteGetStreamAsync(dataUrl);
}
If order of the reports is important (so the ones with higher numbers should always be after those with lower numbers) you should do something like that:
var counter = 0L;
Timer timer = new Timer
(
async _ =>
{
var local = Interlocked.Read(ref counter);
Interlocked.Increment(ref counter);
await ReportMonitoring(1);
if (local % 2 == 0)
{
await ReportMonitoring(2);
}
if (counter % (3 * 12) == 0)
{
await ReportMonitoring(3);
await ReportMonitoring(4);
await ReportMonitoring(5);
}
},
null,
TimeSpan.Zero,
TimeSpan.FromMinutes(5)
);
Also note that:
As long as you are using a Timer, you must keep a reference to it. As with any managed object, a Timer is subject to garbage collection when there are no references to it. The fact that a Timer is still active does not prevent it from being collected.
Out of curiosity I have also tried the same kind of logic with System.Timers. I created the timer instance in the class so that it won't get disposed when the method closes. In the method I have assigned required values to the timer properties. Because System.Timers have an ability to run events at intervals I have used #Guru's logic from above into the event to invoke my ReportMonitoring Method. I hope it comes handy to someone in future.
using System;
using System.Threading;
using System.Timers;
using _logger = DemoProject.Common.Service;
namespace ReportMonitoringService
{
public class Worker
{
private System.Timers.Timer timer = new System.Timers.Timer();
private double _intervalTime = 300000; // 5mins
private bool _timerInUse = false;
private long _counter = 0L;
private async void StartMonitoringTimer()
{
try
{
timer.Elapsed += new ElapsedEventHandler(this.ReportDownload);
timer.Interval = _intervalTime; //5 mins in milliseconds
timer.Enabled = true;
}
catch (Exception ex)
{
await _logger.Error($"Monitoring failed exception: {ex}");
}
}
private async void ReportDownload(object source, ElapsedEventArgs e)
{
var local = Interlocked.Read(ref _counter);
Interlocked.Increment(ref _counter);
if (_timerInUse == false)
{
_timerInUse = true;
try
{
int _numReports;
if (local % 2 == 0) { _numReports = 2; }
else if (_counter % (3 * 12) == 0) { _numReports = 5; }
else { _numReports = 1; }
await ReportMonitoring(_numReports);
}
catch (Exception ex)
{
await _logger.Error($"Timer function threw exception downloading from Server");
await AppendLogtoFile("error: {ex.Message} stack trace: {ex.StackTrace}", LogType.Error);
}
_timerInUse = false;
}
}
}
}

What is the best way to cancel operation anywhere in a method?

Suppose I have a long operation inside a subroutine or function and I want to be able to cancel (exit subroutine or function) immediately after a "cancellation flag" is set to true. What is the best way to do it? One way is to check the flag after each line of code but that is not very elegant.
For example:
dim _CancelFlag as boolean = false
Sub LongOperation()
dim a as integer
a = 1
if _CancelFlag = True Then
Exit Sub
End If
a = 2
if _CancelFlag = True Then
Exit Sub
End If
'And so on...
End Sub
Of course a = 1 is only for illustration purpose. Say the operation is really long until a = 100 and it is not possible to put them into a loop, how can I trigger the cancellation from outside of the subroutine and stop it immediately?
I was thinking to put the sub into a BackgroundWorker or Task but then I still have to check for CancellationToken somewhere inside the sub.. Do I really have to check after each line of code?
It depends on the granularity you want to achieve: how many seconds can you expect your method be canceled?
If the cancellation must take place "immediately" you have to check in as many place as you can. However, just checking before and after long sub steps of your operation is enough in the general case.
Remember that if you have to wait on handles, you have to use the appropriate overload that specifies a timeout or a cancellation token.
Additionally, you should propagate the cancellation token/your flag deep down your methods to allow detection early the cancellation requests.
I found a more elegant way to do it, although it does use a loop in the end. Please let me know if anybody has an better solution. I will also update when I find something else.
Sub LongOperation()
dim state as integer = 0
Do while state < 100
Select Case state
Case 0
a = 1
Case 1
a = 2
Case Else
Exit do
End Select
If _CancelFlag = True Then
Exit Sub
End If
state += 1
Loop
End Sub
This is a sample windows application I have created to cancel or pause the log running task.
public partial class Form1 : Form
{
updateUI _updateGUI;
CancellationToken _cancelToken;
PauseTokenSource _pauseTokeSource;
public Form1()
{
InitializeComponent();
}
delegate void updateUI(dynamic value);
private void btnStartAsync_Click(object sender, EventArgs e)
{
_pauseTokeSource = new PauseTokenSource();
_cancelToken = default(CancellationToken);
_pauseTokeSource.onPause -= _pauseTokeSource_onPause;
_pauseTokeSource.onPause += _pauseTokeSource_onPause;
Task t = new Task(() => { LongRunning(_pauseTokeSource); }, _cancelToken);
t.Start();
}
private void _pauseTokeSource_onPause(object sender, PauseEventArgs e)
{
var message = string.Format("Task {0} at {1}", e.Paused ? "Paused" : "Resumed", DateTime.Now.ToString());
this.Invoke(_updateGUI, message);
}
private async void LongRunning(PauseTokenSource pause)
{
_updateGUI = new updateUI(SetUI);
for (int i = 0; i < 20; i++)
{
await pause.WaitWhilePausedAsync();
Thread.Sleep(500);
this.Invoke(_updateGUI, i.ToString() + " => " + txtInput.Text);
//txtOutput.AppendText(Environment.NewLine + i.ToString());
if (_cancelToken.IsCancellationRequested)
{
this.Invoke(_updateGUI, "Task cancellation requested at " + DateTime.Now.ToString());
break;
}
}
_updateGUI = null;
}
private void SetUI(dynamic output)
{
//txtOutput.AppendText(Environment.NewLine + count.ToString() + " => " + txtInput.Text);
txtOutput.AppendText(Environment.NewLine + output.ToString());
}
private void btnCancelTask_Click(object sender, EventArgs e)
{
_cancelToken = new CancellationToken(true);
}
private void btnPause_Click(object sender, EventArgs e)
{
_pauseTokeSource.IsPaused = !_pauseTokeSource.IsPaused;
btnPause.Text = _pauseTokeSource.IsPaused ? "Resume" : "Pause";
}
}
public class PauseTokenSource
{
public delegate void TaskPauseEventHandler(object sender, PauseEventArgs e);
public event TaskPauseEventHandler onPause;
private TaskCompletionSource<bool> _paused;
internal static readonly Task s_completedTask = Task.FromResult(true);
public bool IsPaused
{
get { return _paused != null; }
set
{
if (value)
{
Interlocked.CompareExchange(ref _paused, new TaskCompletionSource<bool>(), null);
}
else
{
while (true)
{
var tcs = _paused;
if (tcs == null) return;
if (Interlocked.CompareExchange(ref _paused, null, tcs) == tcs)
{
tcs.SetResult(true);
onPause?.Invoke(this, new PauseEventArgs(false));
break;
}
}
}
}
}
public PauseToken Token
{
get
{
return new PauseToken(this);
}
}
internal Task WaitWhilePausedAsync()
{
var cur = _paused;
if (cur != null)
{
onPause?.Invoke(this, new PauseEventArgs(true));
return cur.Task;
}
return s_completedTask;
}
}
public struct PauseToken
{
private readonly PauseTokenSource m_source;
internal PauseToken(PauseTokenSource source) { m_source = source; }
public bool IsPaused { get { return m_source != null && m_source.IsPaused; } }
public Task WaitWhilePausedAsync()
{
return IsPaused ?
m_source.WaitWhilePausedAsync() :
PauseTokenSource.s_completedTask;
}
}
public class PauseEventArgs : EventArgs
{
public PauseEventArgs(bool paused)
{
Paused = paused;
}
public bool Paused { get; private set; }
}
If your LongOperation() is well splittable into short operations (I assume a=1, a=2, ..., a=100 being all reasonably short) than you could wrap all the short operations into Tasks, put them into a TaskQueue and process that queue, checking between the Tasks if cancellation was requested.
If LongOperation() is difficult to split you could run the LongOperation() on a separate dedicated thread and abort that thrad on cancellation. Some have commented aborting a thread being dirty and not being recommended. Actually that's not that bad, if properly handled. Aborting a thread just raises a ThradAbortException within the thread method. So if there is a try - catch - finally in the LongOperation(), catching and handling the exception and if the finally code properly does cleanup, closes all handles, disposes etc., this should be ok and nothing to be afraid of.

Wait for all threads to release semaphore?

How do I close down and wait for a semaphore to be fully released?
private SemaphoreSlim _processSemaphore = new SemaphoreSlim(10);
public async Task<Modification> Process(IList<Command> commands)
{
Assert.IsFalse(_shuttingDown, "Server is in shutdown phase");
await _processSemaphore.WaitAsync();
try
{
// threads that have reached this far must be allowed to complete
return _database.Process(commands);
}
finally
{
_processSemaphore.Release();
}
}
public async Task StopAsync()
{
_shuttingDown = true;
// how wait for threads to complete without cancelling?
await ?
}
private SemaphoreSlim _processSemaphore = new SemaphoreSlim(10);
private int _concurrency;
private TaskCompletionSource<int> _source;
private ManualResetEvent _awaitor;
public void Start()
{
//solution 1
_concurrency = 0;
_source = new TaskCompletionSource<int>();
_shuttingDown = false;
//solution 2
_awaitor = new ManualResetEvent(false);
//your code
}
public async Task<Modification> Process(IList<Command> commands)
{
Interlocked.Increment(ref _concurrency);
Assert.IsFalse(_shuttingDown, "Server is in shutdown phase");
await _processSemaphore.WaitAsync();
try
{
// threads that have reached this far must be allowed to complete
return _database.Process(commands);
}
finally
{
_processSemaphore.Release();
//check and release
int concurrency = Interlocked.Decrement(ref _concurrency);
if (_shuttingDown && concurrency == 0)
{
//solution 1
_source.TrySetResult(0);
//solution 2
_awaitor.Set();
}
}
}
public async Task StopAsync()
{
_shuttingDown = true;
// how wait for threads to complete without cancelling?
if (Interlocked.CompareExchange(ref _concurrency, 0, 0) != 0)
{
await _source.Task;//solution 1
_awaitor.WaitOne();//solution 2
}
}
Might not be exactly what you need, but I had a similar case and I solved it with the CountdownEvent class
private CountdownEvent _countdownEvent = new CountdownEvent(1);
process_method() {
//if the count is zero means that we already called finalize
if (_countdownEvent.IsSet)
return;
try
{
//this can throw and exception if we try to add when the countdown has already reached 0.
//this exception happens when one process_method B has passed the _counddownEvent.IsSet check and context switched to
//to another process_method A that was the last one (after finalize waits for 0) and sets the countdown to 0. Which
//triggers finalization and should not allow new process_method, so process_methodB not continuing is good (finalization is
//in progress).
_countdownEvent.AddCount(1);
} catch
{
return;
}
try
{
//your process
}
finally
{
_countdownEvent.Signal();
}
}
And then when you are ready to wait for the count to be zero:
finalize() {
_countdownEvent.Signal();
_countdownEvent.Wait(_finalizationSafetyTimeout, cancellationToken)
}

Disposing a manualResetevent on another thread

Similar to this question I have a class with a private ManualReset event:
class A {
private ManualResetEvent mre = new ManualResetEvent(true);
private void Method(){
//do something
mre.Reset();
}
public bool WaitForItem(int timeout){
try{
return mre.WaitOne(timeout)
}catch(ObjectDisposedException){
return false;
}
}
public void Dispose(){
mre.Dispose();
}
}
How can I check that when Dispose is called WaitForItem method returns false, and doesn't block waiting.
The code is something similar to:
A a = new A(1);
a.Method();
bool finished = true;
Thread t1 = new Thread(() =>
{
finished = a.WaitForItem(Timeout.Infinite);
});
Thread t2 = new Thread(() =>
{
a.Dispose();
});
t1.Start();
t2.Start();
t1.Join();
t2.Join();
The code blocks in waiting an item forever (at t1.Join()). I understood that calling Close, which is also a mean of disposing an object, doesn't affect the state of the handle, but how can I exit the method with false (catching an ObjectDisposedException) ?
Even though instead of calling a.Dispose() on the second thread calling another method which Disposes the ManualResetEvent the call to WaitOne() it's blocked.
The ObjectDisposedException is raised only when an object is already disposed before calling a member function. This is not happening in your case as function mre.WaitOne(timeout) is called before mre.Dispose().
Once simple fix could be to call mre.WaitOne(timeout) function in a loop with a shorter timeout value. e.g. one want to have 10 seconds timeout for WaitForItem function then mre.WaitOne(timeout) can be called with just 1 sec timeout and it will give up after 10 tries.
A typical implementation could for WaitForItem function is explained below. WaitForItem has got 3 possible return values.
1 = Set is triggered on mre
0 = Set is not triggered within specified timeout
-1 = Object is dispose before timeout.
public int WaitForItem(int timeout){
try{
int nReturnCode = 0;
int nTimeElapsed = 0;
while (true)
{
if (mre.WaitOne(1000)) //just wait for 1 second
{
nReturnCode = 1; //Set call on ManualResetEvent
break;
}
else //Timeout need to repeat
{
nTimeElapsed += 1000;
if (nTimeElapsed > timeout)
{
nReturnCode = 0; //timeout
break;
}
}
}
return nReturnCode;
}catch(ObjectDisposedException){
return -1; //Exception
}
}

Categories