Piggybacking data on EventArgs or sender for an EventHandler - c#

I am writing a custom scheduler and as such I want to fire off whatever tasks are registered to be run at the current time, without taking so much time that the scheduler misses the next time slot. I have therefore created a thread that sleeps until the next scheduled event and then it wakes and runs that next event or events and then it sleeps again. Tasks are run as processes in the background so I can just set them up and fire them off as quickly as possible. In order to facilitate logging for the controlling process I keep an internal queue of tasks that upon waking, I consume as I fire off the processes, but I also want to have an EventHandler that can then finish the logging for that task by registering how long it took and whether it failed or succeeded once it exits.
Because I am using the Process.Process() class to execute the task in the background, there is no way (I can see) to pass my unique task reference through to the handler so I can finish the logging correctly. I am setting up my handler like the code below.
pTask = new Process();
pTask.Exited += new EventHandler(pTask_Exited);
I deliberately used the term piggyback in my title because in my research I came across a similar question which attracted one answer that said if you need to piggyback data on EventArgs, your design is flawed. I can accept my design may be flawed, but have not been able to find enlightenment as to how I should design it differently and more effectively. Any guidance is appreciated.

You can achieve this using lambdas as follows:
First define a method that will be run when the process exits. This will be instead of any event handler you are currently using, and performs the necessary logging etc.:
void ExitHandler(Process process, YourTaskInfo taskInfo) // YourTaskInfo is some class that contains data about the task that needs to be passed to the handler
{
Console.WriteLine("Process for task: {0} exited with code: {1}", taskInfo, process.ExitCode);
}
You can then attach this method to the Exited event handler as follows:
pTask.Exited += (s,e) => ExitHandler(pTask, taskInfo);
In this way, you can pass in your unique task reference (taskInfo) to the Exited handler, without worrying about any "piggybacking" etc. on the sender or EventArgs.

Get the data from the Process itself, which is passed as the sender:
void pTask_Exited(object sender, EventArgs e)
{
Process p = (Process)sender;
TimeSpan duration = p.ExitTime - p.StartTime;
bool success = p.ExitCode == 0;
}

Related

What happens if a new Entry is written to the Event Log while the application is inside the handler for a previous entry being written?

My application needs to review all new application Event Log entries as they come in.
private void eventLog_Application_EntryWritten(object sender, EntryWrittenEventArgs e)
{
// Process e.Entry
}
What I would like to know is what happens if another Entry is written to the EventLog while a previous Entry is being handled?
The documentation for EventLog.EntryWritten Event provides an example of handling an entry written event which uses threading (which is why I am asking the question).
In this example they use System.Threading and call the WaitOne() and Set() methods on the AutoResetEvent class, however I'm not sure precisely what this code is intended to achieve.
The documentation states that - WaitOne() "blocks the current thread until the current WaitHandle receives a signal", and that Set() "sets the state of the event to signaled, allowing one or more waiting threads to proceed". I'm not sure what the threading portion of this example is intended to demonstrate, and how this relates to how (or if) it needs to be applied in practice.
It appears that WaitOne() blocks the thread immediately after the entry has been written, until it has been handled, where it is then set to signalled (using Set()), before allowing the thread to proceed. Is this the one and only thread for the application?
Most importantly, when my application is not responsible for writing the the events which need to be read from the EventLog, how should this principle be applied? (If, indeed, it needs to be applied.)
What does happen if a new Entry is written while the application is inside the handler?
Nothing dramatic happens, it is serialized by the framework. The underlying winapi function that triggers the EventWritten event is NotifyChangeEventLog(). The .NET Framework uses the threadpool to watch for the event to get signaled with ThreadPool.RegisterWaitForSingleObject(). You can see it being used here.
Which is your cue to why the MSDN sample uses ARE (AutoResetEvent). The event handler runs on that threadpool thread, exactly when that happens is unpredictable. The sample uses a console mode app, without that ARE it would immediately terminate. With the ARE, it displays one notification and quits. Not actually that useful of course, I would personally just have used Console.ReadLine() in the sample so it just keeps running and continues to display info until you press the Enter key.
You don't need this if you use a service or a GUI app, something that's going to run for a long time until the user explicitly closes it. Note the EventLog.SynchronizingObject property, makes it easy to not have to deal with the threadpool thread in a Winforms app.
The example is not really helping to explain the way the AutoResetEvent works in a multi-threaded scenario, so I'll try to explain how I understand it to work.
The AutoResetEvent signal static variable, is instantiated as a new AutoResetEvent with its signaled state set to false, or "non-signaled", meaning that calling signal.WaitOne() will cause the thread that called WaitOne to wait at that point, until the signal variable is "set" by calling the signal.Set() method.
I found an explanation of AutoResetEvent that describes it very well in understandable real-world terms, which also included this excellent example below.
http://www.albahari.com/threading/part2.aspx#_AutoResetEvent
AutoResetEvent
An AutoResetEvent is like a ticket turnstile: inserting a ticket lets
exactly one person through. The “auto” in the class’s name refers to
the fact that an open turnstile automatically closes or “resets” after
someone steps through. A thread waits, or blocks, at the turnstile by
calling WaitOne (wait at this “one” turnstile until it opens), and a
ticket is inserted by calling the Set method. If a number of threads
call WaitOne, a queue builds up behind the turnstile. (As with locks,
the fairness of the queue can sometimes be violated due to nuances in
the operating system). A ticket can come from any thread; in other
words, any (unblocked) thread with access to the AutoResetEvent object
can call Set on it to release one blocked thread.
class BasicWaitHandle
{
static EventWaitHandle _waitHandle = new AutoResetEvent (false);
static void Main()
{
new Thread (Waiter).Start();
Thread.Sleep (1000); // Pause for a second...
_waitHandle.Set(); // Wake up the Waiter.
}
static void Waiter()
{
Console.WriteLine ("Waiting...");
_waitHandle.WaitOne(); // Wait for notification
Console.WriteLine ("Notified");
}
}
According to https://msdn.microsoft.com/en-us/library/0680sfkd.aspx the eventlog components are not thread-safe and that code is there to prevent unexpected behaviour in simultaneous interactions.
If multiple threads are executing these lines simultaneously, if is possible for one thread to change the EventLog.Source Property of the event log, and for another thread to write a message, after that property had been changed.

How do I have the main thread wait for other threads when using the Event-based Asynchronous Pattern?

I have a main thread that starts a few worker threads through a class that implements the Event-based Asynchronous Pattern (http://msdn.microsoft.com/en-us/library/ms228969.aspx). Unfortunately, as soon as the main thread is done setting up the worker threads, it exits.
I want the main thread to wait indefinitely until the anEventHandler method is called, then process that method. The asyncevents listen for events indefinitely until canceled, so they might call the anEventHandler method multiple times before completing.
NOTE: There is no related GUI, I'm just using this pattern.
public static void Main(String[] args) {
AsyncEventClass asyncevent = new AsyncEventClass();
// setup event handling
asyncevent.Events += new EventsHandler(anEventHandler);
// start event monitoring threads
asyncevent.monitorAsync(1);
asyncevent.monitorAsync(2);
asyncevent.monitorAsync(3);
System.Console.WriteLine("The main thread now ends. :(");
}
All the examples online use System.Console.ReadLine(), but that seems like a terrible idea in production code.
You can use a simple AutoResetEvent which you wait for in the main method, and set in the event handler.
If you want to wait for a specific amount of times that the eventhandler is called, I guess you can keep a counter, and set the auto-reset-event only when you reach a certain threshold.
I ended up putting all of the IAsyncResutl objects returned by calling WorkerEventHandler.BeginInvoke into a list, and then exposing that list to the Main method. There, I setup all the asyncevents I need to listen for, then use WaitHandle.WaitAll to wait for the events to complete.

Kill event thread

I have a timer event that fires every second. Sometimes when I exit the program (in the VS debugger), it tells me that the event thread is trying to access an object that no longer exists (because the main thread is over). I tried disabling the event before I exit (UpdateTime.aTimer.Enabled = false;). This cut down the number of times this problem occurs, but it still happens sometimes because the event fires before I can disable it.
Is this a serious problem? Will is haunt me if I don't deal with it?
If yes to the above, how do I kill it?
I ask the second question because I have no reference to the event thread, so I don't know how I can tell it to stop or wait for it to finish.
EDIT: More context. This is a Winform.
Also, I'm not explicitly creating a thread. It's my understanding that a thread is automatically created to handle events.
Creating the timer:
public static void Update(){
System.Timers.Timer aTimer = new System.Timers.Timer(1000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Enabled = true;
}
Event handler:
private static void OnTimedEvent(object source,ElapsedEventArgs e) {
Form1obj.updateLabel(String.Format("{0}", DateTime.Now.Second),Label1);
}
Closing program handler:
private void Form1_FormClosing(object sender,FormClosingEventArgs e) {
aTimer.Enabled = false;
}
Serious Problem? Probably not, but I don't think a problem needs to be serious to need to be fixed. Warnings should be treated as errors in compilation, for example. In addition, if this is an app sent to clients, showing ugly errors on shutdown is not very professional.
How to solve this depends on how you are setting up the threads ("event thread" does not give enough info about the mechanics). One easy method might be to stall the main thread for a bit when the application shuts down until the threads all return. You have to also stop issuing new threads during this time.
Another possible solution would be to handle how the threads are created so you can shut down the process that fires them. Concepts like ThreadPool come to mind. Also ensuring threads are background threads, explicitly, can help in some situations.
The short answer is nobody will be able to give you a firm "this will fix your issue" answer without some context of what you are doing in your code.
ADDED:
There are a couple of "quick, down and dirty" ways to handle this. Don't have time for full analysis, so see if they work.
Just cure the error by waiting
Add a counter and wait until incremented down
The first thing I would consider is adding a safety net to not update the label when in a shutdown condition. That is regardless of anything else, as that is where your errors are firing. I don't think "main thread is not present" is the core of the issue, but rather this line:
Form1obj.updateLabel(String.Format("{0}", DateTime.Now.Second),Label1);
How can you update something that no longer exists? Yes, it is on the main thread, so technically ...
A simple wait would be something like:
private void Form1_FormClosing(object sender,FormClosingEventArgs e)
{
aTimer.Enabled = false;
Thread.Sleep(5000);
}
Hiding the form is also not a bad idea, so the user does not see this?
If you want to use a more "COM like approach", you can add a counter. Increment on Update() (when the event is fired) and decrement on OnTimedEvent(). Make sure you lock the counter when changing it so you do not end up with two threads changing it at the same millisecond. You can then wait until the counter is 0 to finish form close or application unload.
Once again, these are quick, down and dirty, approaches, but they can save you from the error. I am sure someone with more time can come up with a more elegant solution.
You can close the window as suggested in MSDN - when you set the timer to be disabled during shutdown processing, set a flag that your Elapsed event handler can check to know that no more work is needed.
Elapsed events can occur after the
Dispose or Stop method has been called
or after the Enabled property has been
set to false, because the signal to
raise the Elapsed event is always
queued for execution on a thread pool
thread. One way to resolve this race
condition
is to set a flag that tells the event
handler for the Elapsed event to
ignore subsequent events.
Its hard to give a general awnser to the question if its serious or not, it depends entiry on what the timer is doing. what kind of timer is it? a system.Threading one or one of the UI timers?
If possible try and refactor your code so that you can tell the timer to stop firing, if only for the reason not to confuse the users with an error message. it could be as simple as sharing a variable or (preferably) using a CancellationToken

How to ensure order of async operation calls?

[This appears to be a loooong question but I have tried to make it as clear as possible. Please have patience and help me...]
I have written a test class which supports an Async operation. That operation does nothing but reports 4 numbers:
class AsyncDemoUsingAsyncOperations
{
AsyncOperation asyncOp;
bool isBusy;
void NotifyStarted () {
isBusy = true;
Started (this, new EventArgs ());
}
void NotifyStopped () {
isBusy = false;
Stopped (this, new EventArgs ());
}
public void Start () {
if (isBusy)
throw new InvalidOperationException ("Already working you moron...");
asyncOp = AsyncOperationManager.CreateOperation (null);
ThreadPool.QueueUserWorkItem (new WaitCallback (StartOperation));
}
public event EventHandler Started = delegate { };
public event EventHandler Stopped = delegate { };
public event EventHandler<NewNumberEventArgs> NewNumber = delegate { };
private void StartOperation (object state) {
asyncOp.Post (args => NotifyStarted (), null);
for (int i = 1; i < 5; i++)
asyncOp.Post (args => NewNumber (this, args as NewNumberEventArgs), new NewNumberEventArgs (i));
asyncOp.Post (args => NotifyStopped (), null);
}
}
class NewNumberEventArgs: EventArgs
{
public int Num { get; private set; }
public NewNumberEventArgs (int num) {
Num = num;
}
}
Then I wrote 2 test programs; one as console app and another as windows form app. Windows form app works as expected when I call Start repeatedly:
But console app has hard time ensuring the order:
Since I am working on class library, I have to ensure that my library works correctly in all app models (Haven't tested in ASP.NET app yet). So I have following questions:
I have tested enough times and it appears to be working but is it OK to assume above code will always work in windows form app?
Whats the reason it (order) doesn't work correctly in console app? How can I fix it?
Not much experienced with ASP.NET. Will the order work in ASP.NET app?
[EDIT: Test stubs can be seen here if that helps.]
Unless I am missing something then given the code above I believe there is no way of guaranteeing the order of execution. I have never used the AsyncOperation and AsyncOperationManager class but I looked in reflector and as could be assumed AsyncOperation.Post uses the thread pool to execute the given code asynchronously.
This means that in the example you have provided 4 tasks will be queued to the thread pool synchronously in very quick succession. The thread pool will then dequeue the tasks in FIFO order (first in first out) but it's entirely possible for one of later threads to be scheduled before an earlier one or one of the later threads to complete before an earlier thread has completed its work.
Therefore given what you have there is no way to control the order in the way you desire. There are ways to do this, a good place to look is this article on MSDN.
http://msdn.microsoft.com/en-us/magazine/dd419664.aspx
I use a Queue you can then Enqueue stuff and Dequeue stuff in the correct order. This solved this problem for me.
The documentation for AsyncOperation.Post states:
Console applications do not synchronize the execution of Post calls. This can cause ProgressChanged events to be raised out of order. If you wish to have serialized execution of Post calls, implement and install a System.Threading.SynchronizationContext class.
I think this is the exact behavior you’re seeing. Basically, if the code that wants to subscribe to notifications from your asynchronous event wants to receive the updates in order, it must ensure that there is a synchronization context installed and that your AsyncOperationManager.CreateOperation() call is run inside of that context. If the code consuming the asynchronous events doesn’t care about receiving them in the correct order, it simply needs to avoid installing a synchronization context which will result in the “default” context being used (which just queues calls directly to the threadpool which may execute them in any order it wants to).
In the GUI version of your application, if you call your API from a UI thread, you will automatically have a synchronization context. This context is wired up to use the UI’s message queueing system which guarantees that posted messages are processed in order and serially (i.e., not concurrently).
In a Console application, unless if you manually install your own synchronization context, you will be using the default, non-synchronizing threadpool version. I am not exactly sure, but I don’t think that .net makes installing a serializing synchronization context very easy to do. I just use Nito.AsyncEx.AsyncContext from the Nito.AsyncEx nuget package to do that for me. Basically, if you call Nito.AsyncEx.AsyncContext.Run(MyMethod), it will capture the current thread and run an event loop with MyMethod as the first “handler” in that event loop. If MyMethod calls something that creates an AsyncOperation, that operation increments an “ongoing operations” counter and that loop will continue until the operation is completed via AsyncOperation.PostOperationCompleted or AsyncOperation.OperationCompleted. Just like the synchronization context provided by a UI thread, AsyncContext will queue posts from AsyncOperation.Post() in the order it receives them and run them serially in its event loop.
Here is an example of how to use AsyncContext with your demo asynchronous operation:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting SynchronizationContext");
Nito.AsyncEx.AsyncContext.Run(Run);
Console.WriteLine("SynchronizationContext finished");
}
// This method is run like it is a UI callback. I.e., it has a
// single-threaded event-loop-based synchronization context which
// processes asynchronous callbacks.
static Task Run()
{
var remainingTasks = new Queue<Action>();
Action startNextTask = () =>
{
if (remainingTasks.Any())
remainingTasks.Dequeue()();
};
foreach (var i in Enumerable.Range(0, 4))
{
remainingTasks.Enqueue(
() =>
{
var demoOperation = new AsyncDemoUsingAsyncOperations();
demoOperation.Started += (sender, e) => Console.WriteLine("Started");
demoOperation.NewNumber += (sender, e) => Console.WriteLine($"Received number {e.Num}");
demoOperation.Stopped += (sender, e) =>
{
// The AsyncDemoUsingAsyncOperation has a bug where it fails to call
// AsyncOperation.OperationCompleted(). Do that for it. If we don’t,
// the AsyncContext will never exit because there are outstanding unfinished
// asynchronous operations.
((AsyncOperation)typeof(AsyncDemoUsingAsyncOperations).GetField("asyncOp", BindingFlags.NonPublic|BindingFlags.Instance).GetValue(demoOperation)).OperationCompleted();
Console.WriteLine("Stopped");
// Start the next task.
startNextTask();
};
demoOperation.Start();
});
}
// Start the first one.
startNextTask();
// AsyncContext requires us to return a Task because that is its
// normal use case.
return Nito.AsyncEx.TaskConstants.Completed;
}
}
With output:
Starting SynchronizationContext
Started
Received number 1
Received number 2
Received number 3
Received number 4
Stopped
Started
Received number 1
Received number 2
Received number 3
Received number 4
Stopped
Started
Received number 1
Received number 2
Received number 3
Received number 4
Stopped
Started
Received number 1
Received number 2
Received number 3
Received number 4
Stopped
SynchronizationContext finished
Note that in my example code I work around a bug in AsyncDemoUsingAsyncOperations which you should probably fix: when your operation stops, you never call AsyncOperation.OperationCompleted or AsyncOperation.PostOperationCompleted. This causes AsyncContext.Run() to hang forever because it is waiting for the outstanding operations to complete. You should make sure that your asynchronous operations complete—even in error cases. Otherwise you might run into similar issues elsewhere.
Also, my demo code, to imitate the output you showed in the winforms and console example, waits for each operation to finish before starting the next one. That kind of defeats the point of asynchronous coding. You can probably tell that my code could be greatly simplified by starting all four tasks at once. Each individual task would receive its callbacks in the correct order, but they would all make progress concurrently.
Recommendation
Because of how AsyncOperation seems to work and how it is intended to be used, it is the responsibility of the caller of an asynchronous API that uses this pattern to decide if it wants to receive events in order or not. If you are going to use AsyncOperation, you should document that the asynchronous events will only be received in order by the caller if the caller has a synchronization context that enforces serialization and suggest that the caller call your API on either a UI thread or in something like AsyncContext.Run(). If you try to use synchronization primitives and whatnot inside of the delegate you call with AsyncOperation.Post(), you could end up putting threadpool threads in a sleeping state which is a bad thing when considering performance and is completely redundant/wasteful when the caller of your API has properly set up a synchronization context already. This also enables the caller to decide that, if it is fine with receiving things out of order, that it is willing to process events concurrently and out of order. That may even enable speedup depending on what you’re doing. Or you might even decide to put something like a sequence number in your NewNumberEventArgs in case the caller wants both concurrency and still needs to be able to assemble the events into order at some point.

How can I tell if a thread is finished executing without polling ThreadState?

Is there an elegant way to know when a worker thread is done executing so I can access resources it produced?
For example if the worker thread queried a list of SQL Servers using
ServersSqlDataSourceEnumerator.Instance.GetDataSources();
and saved the result in a DataTable variable, what mechanism can I use to know when this DataTable variable has been populated/is available. I don't want to poll ThreadState; it would be ideal to fire an event when it's done so I can perform actions with the result.
Thanks!
You can use a callback mechanism or block on an event to know of completion of an Async operation. See this page for the Asychronous Programming Model in .net - you can call BeginInvoke on any delegate to perform the action in an Async manner.
If you're using the BackgroundWorker type, you can subscribe to the RunWorkerCompleted event.
So fire an event :-P
You could also look at using an AutoResetEvent:
http://msdn.microsoft.com/en-us/library/system.threading.autoresetevent.aspx
What I do in this instance is get the WorkerThread to call a function after it has completed the work, which will invoke the the UI Thread, which can do the work in which you require.
E.g.
private void SetWorkerThreadToDoWork()
{
WorkerThread.Start();
}
private void MyWorkerThreadWork()
{
//This will be on the WorkerThread (called from WorkerThread.Start())
DoWorkFunc();
WorkComplete();
}
private void WorkComplete()
{
if(InvokeRequired == true)
{
//Do the invoke
}
else
{
//Check work done by worker thread
//e.g. ServersSqlDataSourceEnumerator.Instance.GetDataSources();
}
}
If it's a simple process you're using, I'd go for a BackgroundWorkerThread, this comes with it's own events that are fired when work is complete. But if you require to use a Thread, I would either look in to Asynchronous Callbacks or a similar route to that shown above.
You can check my answer on this SO thread
It uses a call back mechanism. When the async operation is done, it will fire the callback method where you can handle the processing that needs to be done post SQL execution.
Use a similar approach to be notified when the asynchronous operation is done.
Hope this helps :)
I don't program in C# but here's what I did with Delphi, maybe you can do it as well with C#.
I have a TThread descendant, and in the "destroy" event I send a message to its creator saying "hey I'm about to die !".
This way its parent (which is the main thread) creates a new one if it needs a new one. To be precise it launches a timer that, when fired, creates a new thread if a new one is needed (sites sucking time (lol) !!).

Categories

Resources