I am using System.Threading.Timer
to asynchronously repeat a certain task. When the task is ready, a method on the original thread (where Start()
was called) should be executed.
public event EventHandler StatusChanged;
public void Start()
{
StatusChanged = new EventHandler(SomethingChangedMethod);
new Timer(Pending, null, 0, 1000);
}
private void Pending(object state)
{
//Do Something
StatusChanged?.Invoke(this, EventArgs.Empty);
}
Since I am not on a control or something, I cannot call Invoke()
or BeginInvoke()
.
CodePudding user response:
Since Start() can be called from outside the library I have no real control about that.
As a library author, you don't know what the right thing to do is. For all you know the original thread was just spun up to call Start
and exited a long time ago. You don't know that returning to the "same" "thread" is the right behaviour, so of course, yes, you leave it up to your consumers.
In the same way that, as a library author, you shouldn't be fixing choices about what logging framework to use, if & how to show error messages to users (if there even are users), etc.
Do the simple thing, raise your event, let the person picking the framework(s) for the application make the right choices. Because you should not (without necessarily impairing the potential consumers of your library)
CodePudding user response:
First off, you may or may not be able to post a message to the thread which called Start
: you'll only be able to do this if the thread has a message queue associated with it, and is checking that queue. UI threads do this, but e.g. threadpool threads, or threads which you've created with new Thread()
, won't.
If a thread has a message queue associated with it, it's common practice to install a SynchronizationContext
on that thread. You can fetch a thread's SynchronizationContext
using SynchronizationContext.Current
, store it away, and then post messages to that thread's message queue using that SynchronizationContext
. If a thread doesn't have a SynchronizationContext
installed on it, SynchronizationContext.Current
returns null
.
public event EventHandler StatusChanged;
private Timer timer;
private SynchronizationContext synchronizationContext;
public void Start()
{
synchronizationContext = SynchronizationContext.Current;
StatusChanged = new EventHandler(SomethingChangedMethod);
timer = new Timer(Pending, null, 0, 1000);
}
private void Pending(object state)
{
// Do Something
if (synchronizationContext != null)
{
synchronizationContext.Post(_ => StatusChanged?.Invoke(this, EventArgs.Empty), null);
}
else
{
StatusChanged?.Invoke(this, EventArgs.Empty);
}
}