SynchronizationContext.Current in async callback - wpf

I am using SynchronizationContext as a means to synchronize to the GUI thread, for WinForms and WPF. Recently I ran into an issue with the old style async callbacks:
private void Button_Click(object sender, RoutedEventArgs e)
{
uiContext = SynchronizationContext.Current;
var cl = new TcpClient();
cl.BeginConnect("127.0.0.1", 22222, ConnectedCallback, null);
}
public void ConnectedCallback(IAsyncResult result)
{
if (SynchronizationContext.Current != uiContext)
uiContext.Post(x => MyUIOperation(), null);
else
MyUIOperation();
}
public void MyUIOperation()
{
Title = "Connected";
}
private SynchronizationContext uiContext;
This will throw an exception, because the SynchronizationContext.Current in the callback function is equal to the captured one, and therefore the UI operation is executed in the worker thread of the callback.
Using this exact same code in WinForms works as I had expected.
For now as a workaround, I am capturing the current ManagedThreadId instead and compare it in the callback. What is correct way to handle this?
Update:
I should add that I am modifying a very old existing class that currently uses the following construct:
if (control.InvokeRequired())
control.BeginInvoke(SomeFunction);
else
SomeFunction();
I am trying to remove the WinForms dependency, without having much impact on the clients of this class. The SomeFunction() is raising events, so if I just call uiContext.Send() or uiContext.Post() , the order of execution is changed since Post() will always queue the call, and Send() will always block.
Also, this is just a very small piece of code to show the root of my issue. In reality the function doing the Post() can be called from the main thread.
This is targeting .NET 4.0

It turned out, in .NET 4.5 the SynchronizationContext is in fact different in the callback function and the if statement would evaluate to true. This was a deliberate change, as discussed here
WPF 4.0 had a performance optimization where it would
frequently reuse the same instance of the
DispatcherSynchronizationContext when preparing the
ExecutionContext for invoking a DispatcherOperation. This
had observable impacts on behavior.
1) Some task-parallel implementations check the reference
equality of the SynchronizationContext to determine if the
completion can be inlined - a significant performance win.
2) But, the ExecutionContext would flow the
SynchronizationContext which could result in the same
instance of the DispatcherSynchronizationContext being the
current SynchronizationContext on two different threads.
The continuations would then be inlined, resulting in code
running on the wrong thread.

Because in my case, the call to MyUIOperation() function would need to
be called immediately if the ConnectedCallback function is called from
the main thread.
That means the call to MyUIOperation() would be a blocking call if the ConnectedCallback is invoked in the UI thread, as opposed to non-blocking if it is invoked from the another thread. This non-determinism could cause other problems down the road.
Just call Send instead. According to this article, the call to Send would just invoke the delegate directly if already in the UI thread.
Also, you could just do Dispatcher.Invoke() instead.

Related

Difference between Dispatcher and TaskSchduler

In WPF both Dispatcher and taskscheduler helps to pass the value from background thread to UI thread. So really what is the difference between them.
For instance in the below code what is the actual Difference between option 1 and option 2
Task<int> tsk = Task<int>.Factory.StartNew(TestMethod);
var threadSchedulder = TaskScheduler.FromCurrentSynchronizationContext();
//Option 1
tsk.ContinueWith((t) =>
{
SetText(tsk.Result);
}, threadSchedulder);
//Option 2
this.Dispatcher.Invoke(() =>
{
SetText(tsk.Result);
});
Both will do almost the same thing and will have its own advantages.
• Dispatcher.BeginInvoke() : Just to Updating something on the UI thread Dispatcher.BeginInvoke is the best option. Typically this is done to update some UI controls with the results of some operation that was executed on a background thread. The Dispatcher.Invoke call will block until this operation completes. We should not execute lengthy operations over here.
Dispatcher.BeginInvoke( () =>{myLabel.Text = "myText"});
• Task.Factory.StartNew() : It is useful when compose multiple tasks together. This makes scheduling work that's dependent on previous tasks far simpler, since you can use Task.WaitAll/Task.WaitAny, as well as continuations.

Send a signal from a pthread to a QObject

I'll try to be explicit. I create a Qt application, that has some buttons and a QTextEdit. Next i create a pthread. And offer the pointer to the MainWindow as the parameter. Something like this:
MainWindow w;
pthread_create(&rThread,NULL,treat,&w);
treat is the function that is executed when the thread is created. Now if i have a pushButton called myButton, and i do somthing like this inside the treat function:
void *treat(void *arg)
{
MainWindow *win = (MainWindow*)arg;
win->ui->myButton->setEnabled(false);
close(pthread_self());
}
It will work fine , and the myButton in my application will disable. However if i do something like this:
void *treat(void *arg)
{
MainWindow *win = (MainWindow*arg;
win->ui->editText->setText("random string");
close(pthread_self());
}
My application will crash with the following error:
QObject: Cannot create children for a parent that is in a different
thread. (Parent is QTextDocument(0x23af2e0), parent's thread is
QThread(0x209a290), current thread is QThread(0x7f7eec000af0) The
program has unexpectedly finished.
As i understand the Ui is living in the main thread, and probably is not accesible in the thread that i created , despite the fact that i offered the pointer of the main window to this thread. But why does disabling of the button work? I am very confused. The reason why i dint use the QThread is because our teacher told me not do it. I have to use pthreads. How could i apply such a change from the pthread to the editText ?
How could i send a signal from a pthread to the other thread in wich the Ui is "living". Thanks in advance guys.
Generally speaking, it's an error to call any of QObject (or derived classes') methods from a thread other than object->thread() - unless they are designed and documented to be thread-safe. There are a few methods in Qt proper that are explicitly documented as being thread safe, for example QCoreApplication::postEvent.
The behavior you're facing is due to accessing QWidget methods from the non-gui thread. It's undefined behavior, so some methods may crash, some won't, but even if they don't it's still undefined behavior that you can't count on. It may depend on the phase of the Moon, for all we know.
The only safe thing to do from another thread is to post an event to the object. When you use QMetaMethod::invoke or QMetaObject::invokeMethod on an object in another thread, Qt will internally post a QMetaCallEvent to the object. Since posting events is thread-safe (can be done from other threads), it's OK to do use either of those invoke methods from other threads. QObject::event() reacts to such events by executing the proper method call.
So, the only thing you can do from the other thread is:
QMetaObject::invokeMethod(win->ui->editText, "setText", Q_ARG(QString, "random string"));
Alas, this is bad design, since you're exposing MainWindow's internal details (like the ui pointer) to outside. What you should do instead is have a setEditText slot on the window:
MainWindow : public QWidget {
...
public:
Q_SLOT void setEditText(const QString & str) {
ui->editText->setText(str);
}
...
};
Then, from the other thread, you do:
QMetaObject::invokeMethod(win, "setEditText", Q_ARG(QString, "random string"));
I fully agree with Marek R's recommendation not to use pthreads when you have QThread available.
First of all mixing libraries when it is not necessary is bad habit. Qt provides QThread and very handy QtConcurrent.
Secondly this is bad design. Create some QObject which will handle yours calculations in thread and will emit signal when it should pass result to UI (main thread). Then create connection and Qt will handle rest of the stuff make it thread safe (by default it will queue connection if signal is passed between threads).
Your code with Qt concurrent:
void *treat(SomeClass *arg) {
arg->doStuff();
}
QtConcurrent::run(treat, someObject);

Multi media timer works fine in release mode but not on debug mode

I'm trying to use mmTimer with a callback function, which is a static CALLBACK function.
I know that a static function cannot call a non-static function, thanks to you all guys, except from the case where the static function gets a pointer to an object as an argument.
the weird thing is that my timer works fine in release mode, and when I try to run it in debug mode there is this unhandeled exception that pops up and breaks the program down.
void CMMTimerDlg::TimerProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
CMMTimerDlg* p = (CMMTimerDlg*)dwUser;
if(p)
{
p->m_MMTimer += p->m_TimeDelay;
p->UpdateData(FALSE);
}
}
my questions are : - is there any way to resolve this problem? - If this error occurs on debug mode, who ensures me that it wouldn't happen once i release the program?
there is where the program stops:
#ifdef _DEBUG
void CWnd::AssertValid() const
{
if (m_hWnd == NULL)
return; // null (unattached) windows are valid
// check for special wnd??? values
ASSERT(HWND_TOP == NULL); // same as desktop
if (m_hWnd == HWND_BOTTOM)
ASSERT(this == &CWnd::wndBottom);
else if (m_hWnd == HWND_TOPMOST)
ASSERT(this == &CWnd::wndTopMost);
else if (m_hWnd == HWND_NOTOPMOST)
ASSERT(this == &CWnd::wndNoTopMost);
else
{
// should be a normal window
ASSERT(::IsWindow(m_hWnd));
// should also be in the permanent or temporary handle map
CHandleMap* pMap = afxMapHWND();
ASSERT(pMap != NULL);
when it gets to pMap it stops at that assertion!!!!
here is the static CALLBACK function
static void CALLBACK TimerProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
here is how I set the timer
UINT unTimerID = timeSetEvent(m_TimeDelay,1,(LPTIMECALLBACK)TimerProc,(DWORD)this,TIME_PERIODIC);
The problem here is that multimedia timer API unlike many other has restrictions on what you are allowed to do inside the callback. You are basically not allowed much and what you are allowed is to update internal structures, do some debug output, and set an synchronization event.
Remarks
Applications should not call any system-defined functions from inside
a callback function, except for PostMessage, timeGetSystemTime,
timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg,
midiOutLongMsg, and OutputDebugString.
Assertion failures start display message boxes which are not allowed and can eventually crash the process. Additionally, windowing API such as IsWindow and friends are not allowed either and are the first place cause leading further to assertion failures.
The best here is to avoid using multimedia timers at all. In most cases you have less restrictive alternate options.
It only looks like your code works in the Release build, it will not assert() that you are doing it right. And you are not doing it right.
The callback from a multi-media timer runs on an arbitrary thread-pool thread. You have to be very careful about what you do in the callback. For one, you cannot directly touch the UI, that code is fundamentally thread-unsafe. So you most certainly cannot call UpdateData(). At best, you update a variable and let the UI thread know that it needs to refresh the window. Use PostMessage(). In general you need a critical section to ensure that your callback doesn't update that variable while the UI thread is using it to update the window.
The assert you get in the Debug build suggests more trouble. Looks like you are not making sure that the timer can no longer callback when the user closes the window. That's pretty hard to solve cleanly, it is a fundamental threading race. PostMessage() will already keep you out of the worst trouble. To do it perfectly clean, you must prevent the window from closing until you know that the timer cannot callback anymore. Which requires setting an event when you get WM_CLOSE and not call DestroyWindow. The timer's callback needs to check that event, call timeKillEvent() and post another message. Which the UI thread can now use to really close the window.
Threading is hard, do make sure that SetTimer() isn't already good enough to get the job done. It certainly will be if the UI update is the only side-effect. You only need timeSetEvent() when you require an accurate timer that needs to do something that is not UI related. Human eyes just don't have that requirement. Only our ears do.

WPF MVVM update label text

My label text isn't updating properly in my 3.5 WPF MVVM app.
The do work part lasts long enough that you can see the waiting mouse pointer.
All I ever see is "Parsed" in the label, which is Bound to InfoText.
the Dispatcher and do work lines are in a Command's method.
Ideas?
The code
Dispatcher.Invoke((Action<string>)SetInfoText, "Start Parsing");
//do work
Dispatcher.Invoke((Action<string>)SetInfoText, "Parsed");
private void SetInfoText(string text)
{
InfoText = text;
}
private string _infoText;
public string InfoText
{
get
{
return _infoText;
}
set
{
_infoText = value;
OnPropertyChanged("InfoText");
}
}
The only thing I can think of to explain it is that you're doing the work on the UI thread. This would prevent the dispatcher from redrawing until your work is done. The work being passed in Invoke is placed in the event queue, meaning it will be performed when idle.
The proper way to fix it is to do the work on a separate thread. If you're looking for workarounds though, look here.
Reference: MSDN
EDIT:
There are lots of ways to perform the work on another thread. Read up on BackgroundWorker, ThreadPool, Task Parallell Library, Threads. :)
Here's a really simple way to do the work in a background thread:
System.Threading.ThreadPool.QueueUserWorkItem( state =>
{
Dispatcher.Invoke((Action<string>)SetInfoText, "Start Parsing");
System.Threading.Thread.Sleep(5000); // Simulate work
Dispatcher.Invoke((Action<string>)SetInfoText, "Parsed");
});
Application.Current.Dispatcher.BeginInvoke(new Action(() => this.InfoText="Start Parsing"));
this works for me.
nevertheless i would put my long running process in a backgroundworker. so ui thread will not get blocked.
edit: if you do all your work in ui thread you should look at the overload for BeginInvoke - you can pass a DispatcherPriority. may be this helps too

WPF: issue updating UI from background thread

My code launches a background thread. The background thread makes changes and wants the UI in the main thread to update. The code that launches the thread then waits looks something like:
Thread fThread = new Thread(new ThreadStart(PerformSync));
fThread.IsBackground = true;
fThread.Start();
fThread.Join();
MessageBox.Show("Synchronization complete");
When the background wants to update the UI, it sets a StatusMessage and calls the code below:
static StatusMessage _statusMessage;
public delegate void AddStatusDelegate();
private void AddStatus()
{
AddStatusDelegate methodForUIThread = delegate
{
_statusMessageList.Add(_statusMessage);
};
this.Dispatcher.BeginInvoke(methodForUIThread, System.Windows.Threading.DispatcherPriority.Send);
}
_statusMessageList is an ObservableCollection that is the source for a ListBox.
The AddStatus method is called but the code on the main thread never executes - that is, _statusMessage is not added to _statusMessageList while the thread is executing. However, once it is complete (fThread.Join() returns), all the stacked up calls on the main thread are executed.
But, if I display a message box between the calls to fThread.Start() and fThread.Join(), then the status messages are updated properly.
What do I need to change so that the code in the main thread executes (UI updates) while waiting for the thread to terminate?
Thanks.
fThread.Join causes your main thread to block until the background thread finishes. As long as the main thread is blocked, the UI cannot be updated.
What you need to do is something like this (untested, but you should get the idea):
void someUiEventThatCausesTheBackgroundProcessingToStart() {
Thread fThread = new Thread(new ThreadStart(PerformSync));
fThread.IsBackground = true;
// disable some UI components here, so that the user cannot
// start the thread a second time
...
fThread.Start();
// *don't* call Thread.Join here, so that your main thread does not block!
}
void PerformSync() {
try {
// do your stuff here
...
} finally {
Dispatcher.Invoke(new Action(ProcessingDone));
}
}
void ProcessingDone() {
// re-enable the UI components
...
MessageBox.Show("Synchronization complete");
}
Of course, in WPF, disabling/enabling UI components is ideally done using some IsBusyProcessing dependency property which is bound with a trigger to the UI elements in question, but this is another story...
EDIT: As another option, you might want to check out the BackgroundWorker class, which contains ProgressChanged and RunWorkerCompleted events that automatically fire in the main thread.
fThread.IsBackground = true;
fThread.Start();
fThread.Join();
The call to Join() is blocking your main thread until the background thread finishes. So the UI thread can't do anything while the other thread is running. You need to not call Join(). If you need to do something on the main thread after the background thread finishes, find another way to do it.
EDIT: The reason it works if you display a message box between the call to Start and Join is because then the main thread is running the message loop for the message box, instead of being blocked at the Join call.
The BackgroundWorker is the right tool for this job. It's no more complicated than is absolutely necessary, gives you all of the hooks that you need for progress reporting, and there's plenty of information available (such as this answer) on how to use it.

Resources