Home > Back-end >  Get EventHandler to call Invoke() on original thread
Get EventHandler to call Invoke() on original thread

Time:10-18

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);
    }
}
  • Related