marshalling events to ui thread using Synchronisation Context - c#

All the examples I have seen using SynchronisationContext.Post have been used in the same class. What I have is the UI thread passing some by-ref arguments to a threadwrapper class, updating the arguments and then I want it to update some labels etc on the UIThread.
internal class ConnThreadWrapper
{
....
public event EventHandler<MyEventArgs<String, Boolean>> updateConnStatus =
delegate { };
public void updateUIThread(string conn, bool connected)
{
uiContext.Post(new SendOrPostCallback((o) =>
{
updateConnStatus(this,
new MyEventArgs<String, Boolean>(conn,
connected));
}),
null);
}
}
//on ui thread
public void updateConnStatus(object sender, MyEventArgs<String, Boolean> e)
{
switch (e.val1)
{
case "CADS" :
if (e.val2 == true)
{
}
The Event seems to fire without any errors but nothing is ever received on the uiThread - i'm not sure if my signature for the sub updateConnStatus is correct or if it works like this. I obviously want the event to handled on the uithread and update the labels from that sub.
In a previous vb.net project I used to reference the form directly on the thread and used a delegate to invoke a callback but apparently this was a bad design as I was mixing application layers. I wanted to use the sync context as it was meant to be thread safe but most of the examples i've seen have used invoke.
Any ideas what I'm missing? Thanks

I wrote this helper class which works for me. Prior to using this class call InitializeUiContext() on UI thread somewhere on application start.
public static class UiScheduler
{
private static TaskScheduler _scheduler;
private static readonly ConcurrentQueue<Action> OldActions =
new ConcurrentQueue<Action>();
public static void InitializeUiContext()
{
_scheduler = TaskScheduler.FromCurrentSynchronizationContext();
}
private static void ExecuteOld()
{
if(_scheduler != null)
{
while(OldActions.Count > 0)
{
Action a;
if(OldActions.TryDequeue(out a))
{
UiExecute(_scheduler, a);
}
}
}
}
private static void UiExecute(TaskScheduler scheduler,
Action a,
bool wait = false)
{
//1 is usually UI thread, dunno how to check this better:
if (Thread.CurrentThread.ManagedThreadId == 1)
{
a();
}
else
{
Task t = Task.Factory.StartNew(a,
CancellationToken.None,
TaskCreationOptions.LongRunning,
scheduler);
if (wait) t.Wait();
}
}
public static void UiExecute(Action a, bool wait = false)
{
if (a != null)
{
if (_scheduler != null)
{
ExecuteOld();
UiExecute(_scheduler, a, wait);
}
else
{
OldActions.Enqueue(a);
}
}
}
}

In the end I ditched the ThreadWrapper and trying to marshal the event to the UI Thread and used a Task instead, in fact I think I can use task to do most of the stuff in this project so happy days.
Task<bool> t1 = new Task<bool>(() => testBB(ref _bbws_wrapper));
t1.Start();
Task cwt1 = t1.ContinueWith(task => { if (t1.Result == true) { this.ssi_bb_conn.BackColor = Color.Green;} else { this.ssi_bb_conn.BackColor = Color.Red; } }, TaskScheduler.FromCurrentSynchronizationContext());
.....
private static bool testBB(ref BBWebserviceWrapper _bbwsw)
{
try
{
//test the connections
if (_bbwsw.initialize_v1() == true)
{
if (_bbwsw.loginUser("XXXXXXXX", "XXXXXXXXX") == true)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
catch
{
return false;
}
}

Related

Invoke method of the control in context of its thread from separate static class

I have a form and some control on it :
public class Tester : Form
{
public Label Demo;
public Label GetDemo()
{
return Demo.Text;
}
}
Also I have some static class :
public static bool Delay(Func<bool> condition)
{
bool result = false;
AutoResetEvent e = new AutoResetEvent(false);
Timer t = new Timer(delegate {
if (result = condition()) e.Set(); // wait until control property has needed value
}, e, 0, 1000);
e.WaitOne();
t.Dispose();
return result;
}
At some point control creates new thread and calls our static method :
ThreadPool.QueueUserWorkItem(delegate {
if (Delay(() => GetDemo() == "X")) MessageBox.Show("X");
}, null);
Of course, this will cause an exception because GetDemo will be passed to Delay and will be called in a new thread as a delegate.
Of course, it is possible to solve it by using Invoke to call our static method :
ThreadPool.QueueUserWorkItem(delegate {
Invoke((MethodInvoker) delegate {
if (Delay(() => GetDemo() == "X")) MessageBox.Show("OK");
}
}, null);
Unfortunately, i am not allowed to change call of Delay, i can change only its implementation.
Question :
1) what needs to be changed INSIDE static method Delay so that condition() would executed GetDemo in its native thread without exceptions?
2) is it possible to do something like this inside Delay?
SynchronizationContext.Dispatcher((Action) delegate {
if (condition()) e.Set();
});
This solution assumes that there is someplace else in your code that you can receive an earlier call on the UI thread, to save off a copy of the UI SynchronizationContext. That may not be the case, in which case my proposed solution won't work.
// Assign this using SynchronizationContext.Current from a call made on the UI thread.
private static SynchronizationContext uiSynchronizationContext;
public static bool Delay(Func<bool> condition)
{
bool result = false;
AutoResetEvent e = new AutoResetEvent(false);
Timer t = new Timer(delegate
{
uiSynchronizationContext.Send(s => result = condition(), null);
if (result)
e.Set(); // wait until control property has needed value
}, e, 0, 1000);
e.WaitOne();
t.Dispose();
return result;
}

Run code only once using dispatcher

I have a simple pattern to run code only once. It's mostly used to Update something on the UI, while it may change very often in the Background.
private bool _updating;
private void UpdateSomething()
{
if (!_updating)
{
_updating = true;
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
_updating = false;
DoSomething();
}), DispatcherPriority.Background);
}
}
I would prefer to put the boilerplate code inside a simple method:
public static void RunOnce(Action action, ref bool guard)
{
if (!guard)
{
guard = true;
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
guard = false;
action();
}), DispatcherPriority.Background);
}
}
und call it like this:
void UpdateSomething()
{
RunOnce(DoSomething, ref _updating);
}
However, this does not work as you cannot have ref parameters inside anonymous methods.
Is there any workaround, e.g. to pin the ref parameter and free it when the method was executed?
You could do something like this:
public static void RunOnce(Action action, ref RunOnceToken token)
{
if (token == null || token.IsCompleted)
{
token = new RunOnceToken(
Application.Current.Dispatcher.BeginInvoke(
action,
DispatcherPriority.Background));
}
}
public sealed class RunOnceToken : IDisposable
{
private DispatcherOperation _operation;
public RunOnceToken(DispatcherOperation operation)
{
if (operation != null &&
operation.Status != DispatcherOperationStatus.Completed &&
operation.Status != DispatcherOperationStatus.Aborted)
{
_operation = operation;
_operation.Completed += OnCompletedOrAborted;
_operation.Aborted += OnCompletedOrAborted;
}
}
private void OnCompletedOrAborted(object sender, EventArgs e)
{
this.Dispose();
}
public bool IsCompleted
{
get { return _operation == null; }
}
public void Dispose()
{
var operation = _operation;
if (operation == null)
return;
_operation = null;
operation.Completed -= OnCompletedOrAborted;
operation.Aborted -= OnCompletedOrAborted;
}
}
Your example usage would change to:
private RunOnceToken _updateToken;
private void UpdateSomething()
{
RunOnce(DoSomething, ref _updateToken);
}
It doesn't really matter if you never clear your copy of the token, because the wrapped DispatcherOperation gets cleared out upon completion to avoid leaking action or any values it captures.
In case it wasn't obvious, none of this is concurrency-safe; I assume everything above is only accessed from the UI thread.
One useful enhancement might be to add an optional DispatcherPriority argument to RunOnce such that you can control the priority level used to schedule action (perhaps canceling an already-scheduled operation if it was scheduled at a lower priority).
I was no aware about DispatcherOperation existence, however seen Mike Strobel answer I wrote following code. I'm not 100% sure about it but it seems to work without to much boilerplate.
public static class DispatcherExtensions {
public static int clearInterval = 10_000;
private static long time => DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
private static long lastClearTime = time;
private static Dictionary<int, DispatcherOperation> currOperations = new Dictionary<int, DispatcherOperation>();
private static object sync = new object();
public static void invokeLastAsync(this Dispatcher d, Action a, DispatcherPriority p = DispatcherPriority.Background, [CallerFilePath]object key1 = null, [CallerLineNumber]object key2 = null) {
lock (sync) {
DispatcherOperation dop;
var k = key1.GetHashCode() ^ key2.GetHashCode();
if (currOperations.ContainsKey(k)) {
dop = currOperations[k];
currOperations.Remove(k);
dop.Abort();
}
dop = d.BeginInvoke(a, p);
clearOperations(false);
currOperations.Add(k, dop);
}
}
public static void clearOperations(bool force = true) {
var ct = time;
if (!force && ct - lastClearTime < clearInterval) return;
var nd = new Dictionary<int, DispatcherOperation>();
foreach (var ao in currOperations) {
var s = ao.Value.Status;
if (s == DispatcherOperationStatus.Completed
|| s == DispatcherOperationStatus.Aborted)
nd.Add(ao.Key, ao.Value);
}
currOperations = nd;
lastClearTime = ct;
}
}
Basically extension method take file path and line number as a key to store DispacherOperation instance in a dictionary, and If the key already have an operation, its aborted and replaced with new operation. Periodically, the dictionary is cleared, from completed/aborted actions that are no longer invoked.
The usage is very simple:
private int initCount = 0;
private int invokeCount = 0;
private void updateSomething() {
initCount++;
view.Dispatcher.invokeLastAsync(() => {
Console.WriteLine($#"invoked {++invokeCount}/{initCount}");
});
}
I haven't run to any issue with this so far. Maybe someone else could see some weak spot.

Freezing GUI Elements

im new here and always find helpful threads here, but not in this case. I'm having an issue with my program using threads. In special, my thread is doing some image pattern in the backround and everything seems to be fine.
It also works an undefined time (sometimes 15 s, sometimes minutes) without any exception or freeze or whatever. But then my GUI freezes, not my whole GUI, just the GUI parts updated from the thread. Two other pictureboxes are working fine(streaming a video), but the rest isnt working.
Trying to stop the thread where it is, works, but starting it from there makes my program collapse.
There arn't eny exceptions thrown. Every GUI element is updated via Invoke() if necessary. I only work on a copy of the Picture to avoid any lockmodes or anything else. Also i try to let the UI doing what it needs to do (DoEvents())
Some ideas?
Code:
namespace My.Name.Space
{
public class MyThread : MyThreadBase
{
public MyThread ( getting object s from the form for updating UI elements)
{
//referencing objects
Stopwatch.Start();
}
//example Method for UI updating
private void UpdateRobot1Box(int angle, int x, int y)
{
if (_rob1.InvokeRequired)
{
_rob1.Invoke(new Action(() => _rob1.Clear()));
_rob1.Invoke(new Action(() => _rob1.Text = angle.ToString() + "°, X:" + x.ToString() + ", Y:" + y.ToString()));
}
else
{
_rob1.Clear();
_rob1.Text = angle.ToString() + "°, X:" + x.ToString() + ", Y:" + y.ToString();
}
}
protected override void Loop(CancellationToken token)
{
while(!token.IsCancellationRequested)
{
if( PictureBox != null && Stopwatch.ElapsedMilliseconds >= tick)
{
//DoWork
Application.DoEvents();
}
else
{
Thread.Sleep(1);
}
}
}
}
}
}
Edit 1:
MyThreadBase:
namespace My.Name.Space
{
public abstract class MyThreadBase : DisposableBase//just some simple gc stuff
{
private CancellationTokenSource _cancellationTokenSource;
public bool IsAlive
{
get { return _cancellationTokenSource != null; }
}
public event Action<Object, Exception> UnhandledException;
public void Start()
{
if (_cancellationTokenSource != null)
return;
lock (this)
{
if (_cancellationTokenSource != null)
return;
_cancellationTokenSource = new CancellationTokenSource();
var thread = new Thread(RunLoop) {Name = GetType().Name};
thread.Start();
}
}
public void Stop()
{
if (_cancellationTokenSource == null)
return;
lock (this)
{
if (_cancellationTokenSource == null)
return;
_cancellationTokenSource.Cancel();
}
}
public void Join()
{
while (IsAlive) Thread.Sleep(1);
}
private void RunLoop()
{
try
{
CancellationToken token = _cancellationTokenSource.Token;
Loop(token);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception exception)
{
OnException(exception);
}
finally
{
lock (this)
{
CancellationTokenSource cancellationTokenSource = _cancellationTokenSource;
_cancellationTokenSource = null;
cancellationTokenSource.Dispose();
}
}
}
protected abstract void Loop(CancellationToken token);
protected virtual void OnException(Exception exception)
{
Trace.TraceError("{0} - Exception: {1}", GetType(), exception.Message);
Trace.TraceError(exception.StackTrace);
OnUnhandledException(exception);
}
protected virtual void OnUnhandledException(Exception exception)
{
if (UnhandledException != null)
UnhandledException(this, exception);
}
protected override void DisposeOverride()
{
Stop();
}
}
The UpdateRobot1Box is called in a switch-case construct within the thread. I got a little for-squence where I go through my list of own created objects to decide what to write in my textbox.
Create a method in main form class to perform the UI update actions:
private void AsyncFormUpdate(Action action)
{
if (this.InvokeRequired)
{
this.Invoke(action, null);
}
else
{
action();
}
}
Having that in proper place you are sure that InvokeRequired acts properly, well, and the code is better encapsulated.
Next be simple. Use the asynchronously invoked delegate with feedback to report angle and coordinates changes to UI, where you'll actually call the AsyncFormUpdate method.
A good example is shown here:
http://www.csharp-examples.net/asynchronous-method-progress/
There they update the progress, where as you'll update the angle and X/Y coordinates.

Monitor doesn't seem to lock the object

I'm trying to implement a basic Future class (yeah, I know about Task but this is for educational purposes) and ran into strange behavior of Monitor class. The class is implemented so that it enters the lock in constructor, queues an action which exits the lock to a thread pool. Result getter checks an instance variable to see if the action is completed and if it isn't, enters lock and then returns the result. Problem is that in fact result getter doesn't wait for the queued action to finish and proceeds anyway leading to incorrect results. Here's the code.
// The class itself
public class Future<T>
{
private readonly Func<T> _f;
private volatile bool _complete = false;
private T _result;
private Exception _error = new Exception("WTF");
private volatile bool _success = false;
private readonly ConcurrentStack<Action<T>> _callbacks = new ConcurrentStack<Action<T>>();
private readonly ConcurrentStack<Action<Exception>> _errbacks = new ConcurrentStack<Action<Exception>>();
private readonly object _lock = new object();
public Future(Func<T> f)
{
_f = f;
Monitor.Enter(_lock);
ThreadPool.QueueUserWorkItem(Run);
}
public void OnSuccess(Action<T> a)
{
_callbacks.Push(a);
if (_complete && _success)
a(_result);
}
public void OnError(Action<Exception> a)
{
_errbacks.Push(a);
if (_complete && !_success)
a(_error);
}
private void Run(object state)
{
try {
_result = _f();
_success = true;
_complete = true;
foreach (var cb in _callbacks) {
cb(_result);
}
} catch (Exception e) {
_error = e;
_complete = true;
foreach (var cb in _errbacks) {
cb(e);
}
} finally {
Monitor.Exit(_lock);
}
}
public T Result {
get {
if (!_complete) {
Monitor.Enter(_lock);
}
if (_success) {
return _result;
} else {
Console.WriteLine("Throwing error complete={0} success={1}", _complete, _success);
throw _error;
}
}
}
// Failing test
public void TestResultSuccess() {
var f = new Future<int>(() => 1);
var x = f.Result;
Assert.AreEqual (1, x);
}
I'm using Mono 3.2.3 on Mac OS X 10.9.
Only the thread that took the lock can exit the lock. You can't Enter it in the constructor on the calling thread then Exit from the thread-pool when it completes - the thread-pool worker does not have the lock.
And conversely: presumably it is the same thread that created the future that is accessing the getter: that is allowed to Enter again: it is re-entrant. Also, you need to Exit the same number of times that you Enter, otherwise it isn't actually released.
Basically, I don't think Monitor is the right approach here.

Joining a thread started with StartNew()

When using the StartNew() method to kick off a process on a new thread, I need to figure out how to make another call into this object in that same thread (I assume this would be some sort of Join operation?).
The following example is dumbed down to illustrate the meat of what I am trying to do. I am well aware it is severely lacking in basic concurrency considerations. But I didn't want to cloud the code with all of that logic, so please forgive me on that.
The following console app shows what I am trying to accomplish. Assume on the StartNew() call a new thread with ID 9976 is created and the method invoked there. I would like the subsequent call to ProcessImmediate() in the file system watcher change event handler to be made on thread 9976 as well. As it stands, the call would share the same thread that is used for the file system watcher change event.
Can this be done, and if so, how?
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var runner = new Runner();
runner.Run();
Console.ReadKey();
}
}
public class Runner
{
private Activity _activity = null;
private FileSystemWatcher _fileSystemWatcher;
public void Run()
{
_activity = new Activity();
// start activity on a new thread
Task.Factory.StartNew(() => _activity.Go());
_fileSystemWatcher = new FileSystemWatcher();
_fileSystemWatcher.Filter = "*.watcher";
_fileSystemWatcher.Path = "c:\temp";
_fileSystemWatcher.Changed += FileSystemWatcher_Changed;
_fileSystemWatcher.EnableRaisingEvents = true;
}
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
// WANT TO CALL THIS FOR ACTIVITY RUNNING ON PREVIOUSLY CALLED THREAD
_activity.ProcessImmediate();
}
}
public class Activity
{
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
System.Threading.Thread.Sleep(2000);
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate()
{
// for purposes of this example, assume that Go is magically in its sleep state when ProcessImmediate is called
DoSomethingInteresting();
}
public bool Stop { get; set; }
}
}
* UPDATE *
Thanks for the excellent responses. I took Mike's suggestion and implemented it for my console app. Below is the full working code which also includes the use of a cancellation token. I post this in case someone else might find it useful.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var runner = new Runner();
runner.Run();
Console.ReadKey();
runner.Stop();
Console.ReadKey();
}
}
public class Runner
{
private Activity _activity = null;
private FileSystemWatcher _fileSystemWatcher;
private CancellationTokenSource _cts = new CancellationTokenSource();
public void Stop() { _cts.Cancel(); }
public void Run()
{
_activity = new Activity();
// start activity on a new thread
var task = new Task(() => _activity.Go(_cts.Token), _cts.Token, TaskCreationOptions.LongRunning);
task.Start();
_fileSystemWatcher = new FileSystemWatcher();
_fileSystemWatcher.Filter = "*.watcher";
_fileSystemWatcher.Path = "C:\\Temp\\FileSystemWatcherPath";
_fileSystemWatcher.Changed += FileSystemWatcher_Changed;
_fileSystemWatcher.EnableRaisingEvents = true;
}
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
// WANT TO CALL THIS FOR ACTIVITY RUNNING ON PREVIOUSLY CALLED THREAD
_activity.ProcessImmediate();
}
}
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
public void Go(CancellationToken ct)
{
Thread.CurrentThread.Name = "Go";
while (!ct.IsCancellationRequested)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(5000);
}
Console.WriteLine("Exiting");
}
protected virtual void DoSomethingInteresting()
{
Console.WriteLine(string.Format("Doing Something Interesting on thread {0}", Thread.CurrentThread.ManagedThreadId));
}
public void ProcessImmediate()
{
// for purposes of this example, assume that Go is magically in its sleep state when ProcessImmediate is called
_processing.Set();
}
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
}
First, you should use TaskCreationOptions.LongRunning if you are creating a task that will not complete quickly. Second, use an AutoResetEvent to signal the waiting thread to wake up. Note that below ProcessImmediate will return before DoSomethingInteresting has completed running on the other thread. Example:
using System.Threading;
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(2000);
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate()
{
_processing.Set();
}
public bool Stop { get; set; }
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
User mike has given a better solution, which will be appropriate when you like to call the same method immediately. If you want to call a different methods immediately I'll expand mike's answer to achieve that.
using System.Threading;
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
private ConcurrentQueue<Action> actionsToProcess = new ConcurrentQueue<Action>();
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(2000);
while(!actionsToProcess.IsEmpty)
{
Action action;
if(actionsToProcess.TryDeque(out action))
action();
}
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate(Action action)
{
actionsToProcess.Enqueue(action);
_processing.Set();
}
public bool Stop { get; set; }
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
To execute different methods on the same thread you can use a message loop that dispatches incoming requests. A simple option would be to use the event loop scheduler of the Reactive Extensions and to "recursively" schedule your Go() function - if in the mean time a different operation is scheduled it would be processed before the next Go() operation.
Here is a sample:
class Loop
: IDisposable
{
IScheduler scheduler = new EventLoopScheduler();
MultipleAssignmentDisposable stopper = new MultipleAssignmentDisposable();
public Loop()
{
Next();
}
void Next()
{
if (!stopper.IsDisposed)
stopper.Disposable = scheduler.Schedule(Handler);
}
void Handler()
{
Thread.Sleep(1000);
Console.WriteLine("Handler: {0}", Thread.CurrentThread.ManagedThreadId);
Next();
}
public void Notify()
{
scheduler.Schedule(() =>
{
Console.WriteLine("Notify: {0}", Thread.CurrentThread.ManagedThreadId);
});
}
public void Dispose()
{
stopper.Dispose();
}
}
static void Main(string[] args)
{
using (var l = new Loop())
{
Console.WriteLine("Press 'q' to quit.");
while (Console.ReadKey().Key != ConsoleKey.Q)
l.Notify();
}
}

Categories