This question already has answers here:
In .NET, what thread will Events be handled in?
(4 answers)
Closed 8 years ago.
pseudo-code:
class A
{
Dictionary<string, object> dic = new Dictionary<string, object>();
public Do()
{
some_a.SomeEvent += (s, e) =>
{
dic["some_string"] = new object();
};
dic["some_other_string"] = new object();
}
}
Is this safe? It would be if both dictionary operations were on single same thread. So are they?
EDIT In my situation event is fired in the same thread as Do, so it's safe.
An event happens (usually) on the thread that invokes the event. So we can't actually comment completely since you don't show the code that causes the event to be invoked!
Strictly speaking, the event could be on any thread - either because a random thread is calling OnSomeEvent (or whatever the trigger is), or if the OnSomeEvent implementation chooses to use BeginInvoke for some reason, but this is unlikely.
Ultimately, it comes down to: is there a reason to think multiple threads are involved in this code.
But: what absolutely is not the case: no, there is nothing that will make that event automatically happen on the thread that subscribes it. An event subscription is just an object+method pair; no thread is nominated in the subscription.
The code inside the event handler will execute on the thread the event is raised on.
class AsyncWorker
{
public void BeginWork()
{
new TaskFactory().StartNew(() => RaiseMyEvent());
}
public event EventHandler MyEvent;
private void RaiseMyEvent()
{
var myEvent = MyEvent;
if(myEvent != null)
myEvent(EventArgs.Empty);
}
}
var worker = new AsyncWorker();
worker.MyEvent += (s, e) =>
{
/* I will be executed on the thread
started by the TaskFactory */
};
worker.BeginWork();
Unless you specifically start the event handler in a different thread, both operations will indeed run on the same thread (assuming a single threaded application).
Related
This question already has answers here:
How to block until an event is fired in c#
(5 answers)
Closed 1 year ago.
I'm pretty sure that this has a relatively easy answer, but somehow I cannot find it.
In examples of console applications that handle events (e.g. https://www.rabbitmq.com/tutorials/tutorial-six-dotnet.html but I've seen many others as well) I see code like this:
public static void Main()
{
var someObject = new MyClassWithEvents();
someObject.SomeEventFired += () =>
{
// do whatever
};
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
Now the obvious problem with this is that if you go beyond example code (where you can wait for a key to be pressed) and remove the Console.ReadLine() the thread exits (or if you're not in Main(), you go out of context) and the events are no longer processed.
I guess I could use an eternal while(true) { Sleep() } but wouldn't that also block the thread from receiving the events?
What would be the correct way of writing this kind of program? The idea is that it looks much like a service, waiting there doing nothing until an event is fired.
To see what I mean, try the following code:
public static void Main()
{
var someObject = new MyClassWithEvents();
someObject.SomeEventFired += () =>
{
// do whatever
};
}
This exits immediately!
TIA,
Jim
Haven't tested this, but I'd try this as the simplest approach:
public static ManualResetEventSlim waiter = new ManualResetEventSlim(false);
public static void Main()
{
var someObject = new MyClassWithEvents();
someObject.SomeEventFired += () =>
{
// do whatever
};
// Just an example for an "Exit-Trigger"
someObject.ExitProgramEventFired += () =>
{
waiter.Set(); // Signal the MRE to stop blocking.
};
waiter.Wait(); // Blocks until signalled.
Console.WriteLine("Exit Program has been triggered.");
// Cleanup resources ...
}
}
Mind: The Wait method also comes with overloads to support cancellation and timeout, so you can really harden your design.
For reference: ManualResetEventSlim
If you're using a newer version of .Net, you can make your entry point a Task Main instead of void Main. Then you can use a TaskCompletionSource to return a task that will finish when the cancel key is pressed.
Doing it this way should free up the main thread back into the Thread pool, which means it should use less resources.
public static Task Main(string[] args)
{
// Set up TaskCompletionSource that completes when the CancelKey is Pressed
var taskCompletionSource = new TaskCompletionSource<bool>();
Console.CancelKeyPress += (_, args) =>
{
args.Cancel = true;
taskCompletionSource.TrySetResult(true);
};
var someObject = new MyClassWithEvents();
someObject.SomeEventFired += () =>
{
// do whatever
};
return taskCompletionSource.Task;
}
Should mention though, you asked 'wouldn't that also block the thread from receiving the events', but that shouldn't be an issue. Callbacks usually don't come back on the main thread, they are usually handled by a random free thread from the thread pool. So even if the main thread is blocked by something, callbacks like that will usually still run.
Issue
I am streaming my camera out and want it to run on a separate thread as my UI is freezing. If I start a Thread on the first method call, does the methods inside that method go into the new thread or the old thread?
This is my setup at the moment.
Code
When the user clicks 'Start Stream':
Thread thread = new Thread(new ThreadStart(StartNewStream));
thread.Name = "streammm";
thread.Start();
This calls 'StartNewStream' method which calls other methods:
cam.OnSampleAvailable += (s, e) =>
{
lock (BusyLock)
rtspRecord.PushVideo(e.Sample);
};
win.OnSamplesAvailable += (s, e) =>
{
lock (BusyLock)
rtspRecord.PushAudio(e.Samples);
};
Do the methods PushVideo and PushAudio get called in the UI thread or the newly created thread?
If I go into the PushVideo method and put the code:
Thread TR = Thread.CurrentThread;
string _name = TR.name;
The name is now null?
Anyone help on what I am doing wrong?
Whichever thread invokes the OnSampleAvailable event or delegate will also execute its handlers. It does not matter which thread assigns the handlers.
You must understand what your code actually does:
cam.OnSampleAvailable += (s, e) =>
{
lock (BusyLock)
rtspRecord.PushVideo(e.Sample);
};
This does not call anything at first. It only assigns an anonymous method (s, e) => { ... } as a handler to the event cam.OnSampleAvailable.
The handler is not called here. The assignment completes and as the end of your StartNewStream method is reached, your new thread ends. Then, much later, there may be samples available on your cam. Whichever thread is responsible (we do not know) will invoke the cam.OnSampleAvailable event, and the handler (the anonymous method (s, e) => { ... } you assigned earlier) will be executed by that unknown thread.
It depends on the implementation of cam and win. Likey either those two events are running on their own thread pool thread or they may run on the UI thread if they are written in a way that knows how to capture the OperationContext
I've the following class:
class Integration
{
public event EventHandler<LogEventArgs> LogMessageEvent
protected virtual void OnLog(LogEventArgs e)
{
if(LogMessageEvent != null)
LogMessageEvent(this, e);
}
public void SomeWork()
{
//Do some things...
var e = new LogMessageEvent("The file was copied...");
OnLog(e);
//Do more things...
var e = new LogMessageEvent("Another thing...");
OnLog(e);
}
}
I need that event subscribers do not block the SomeWork method and that the execution be sequential ("The file was copied..." event execute always first)
I tried with tasks:
Task.Run(... OnLog())....
But the problem is that sometimes a task created later raises an event before a previously created task. (As expected, considering that I'm not doing synchronization.)
I'm suspecting that there is some easiest way to accomplish this task (Call events sequentially and asynchronously ).
Store your last used Task-object and use ContinueWith.
It tells your task to continue with the new event-invocation when the first task has finished. So the event are not triggered in parallel but sequentially.
ContinueWith returns a new Task-object, so you need to update your reference, so the next ContinueWith-call can be successful.
This is not thread-safe but as long as you call it only from one thread it should work (and did perfectly for me).
I have a project here and it has set by default that the actions occur by MouseEnter event. I mean, opening a Window, closing, returning, whatever, happens only by the MouseEnter event.
I was requested to make the event fire only after 3 seconds. That means that the user will place the mouse on the control and only after 3 seconds the event must happen for all the controls in the window.
So, I thought about a global timer or something alike, that will return false untill the timer reaches 3... I think that's the way...
Geez, does anybody knows how can I make such thing?
Thanks!!
You can define a class that will expose a DelayedExecute method that receives an action to execute and creates timers as needed for the delayed execution. It would look something like this:
public static class DelayedExecutionService
{
// We keep a static list of timers because if we only declare the timers
// in the scope of the method, they might be garbage collected prematurely.
private static IList<DispatcherTimer> timers = new List<DispatcherTimer>();
public static void DelayedExecute(Action action, int delay = 3)
{
var dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
// Add the timer to the list to avoid it being garbage collected
// after we exit the scope of the method.
timers.Add(dispatcherTimer);
EventHandler handler = null;
handler = (sender, e) =>
{
// Stop the timer so it won't keep executing every X seconds
// and also avoid keeping the handler in memory.
dispatcherTimer.Tick -= handler;
dispatcherTimer.Stop();
// The timer is no longer used and shouldn't be kept in memory.
timers.Remove(dispatcherTimer);
// Perform the action.
action();
};
dispatcherTimer.Tick += handler;
dispatcherTimer.Interval = TimeSpan.FromSeconds(delay);
dispatcherTimer.Start();
}
}
Then you can call it like this:
DelayedExecutionService.DelayedExecute(() => MessageBox.Show("Hello!"));
or
DelayedExecutionService.DelayedExecute(() =>
{
DoSomething();
DoSomethingElse();
});
I just wanted to add a simpler solution:
public static void DelayedExecute(Action action, int delay = 3000)
{
Task.Factory.StartNew(() =>
{
Thread.Sleep(delay);
action();
}
}
Then use it just like in this other answer
I have the following EventHandler:
private EventHandler<MyEventArgs> _myEventHandler;
public event EventHandler<MyEventArgs> MyEvent
{
add { _myEventHandler += value; }
remove { _myEventHandler -= value; }
}
Could somebody explain the difference between the following snippets?
Snippet EventHandler (A):
//Snippet A:
if (_myEventHandler != null)
{
_myEventHandler(new MyEventArgs());
}
Snippet BeginInvoke (B):
//Snippet B:
if (_myEventHandler != null)
{
_myEventHandler.BeginInvoke(new MyEventArgs(), ar =>
{
var del = (EventHandler<MyEventArgs>)ar.AsyncState;
del.EndInvoke(ar);
}, _myEventHandler);
}
For clarification: What's the difference between invoking an EventHandler "just as it is" and using BeginInvoke?
The BeginInvoke approach is async, meaning that it is raised on a different thread. This can be dangerous if people don't expect it, and is pretty rare for events - but it can be useful.
Also, note that strictly speaking you should snapshot the event handler value - this is especially true if (via Begin*) you are dealing with threads.
var tmp = _myEventHandler;
if(tmp != null) {
tmp(sender, args);
}
Also - note that your event subscription itself is not thread-safe; again, this only matters if you are dealing with multi-threading, but the inbuilt field-like event is thread-safe:
public event EventHandler<MyEventArgs> MyEvent; // <===== done; nothing more
The issues avoided here are:
with the snapshot, we avoid the risk of the last subscriber unsubscribing between the null-check and the invoke (it does mean they might get an event they didn't expect, but it means we don't kill the raising thread)
with the field-like event change we avoid the risk of losing subscriptions / unsubscriptions when two threads are doing this at the same time
BeginInvoke() call immediatelly returns control to the calling thread and run a delegate in a separate thread from the ThreadPool, so this will be some kind of asynchronous execution.