Why i should call Control.Invoke from non-ui thread? - winforms

Why i should call Control.Invoke from non-ui thread? As i know any manipulations with control are the messages to control. So when i call, for example TextBox.Text = "text", it will produce message SendMessage(TextBox.Hanlde...). That message will be queued into UI thread message queue and dispatched by UI thread. Why i have to call invoke, even it will produce the same message?

There are two reasons MS developers made this restriction:
Some UI functions have access to thread-local storage (TLS). Calling these functions from another thread gives incorrect results on TLS operations.
Calling all UI-related functions from the same thread automatically serializes them, this is thread-safe and doesn't require synchronization.
From our point of view, we just need to follow these rules.

Because you cannot directly access UI controls from threads other than the thread they were created on. Control.Invoke will marshal your call onto the correct thread - allowing you to make a call from another thread onto the UI thread without needing to know yourself what the UI thread is or how to perform the marshalling.
Update: to answer your question, you don't have to use Control.Invoke - if you have code to marshal your call onto the correct thread and post a message to the message pump - then use that. This, however, is known as re-inventing the wheel. Unless you are doing something that changes the behaviour.

Related

How to make a GTK application that receives data from a TCP socket

I am building a GUI (using C) which receives data to display from another application sending the data over a TCP socket. How do I do this using GTK (just a general overview of the approach I should take)? I have done a lot of searching and came across stuff about multithreading, GIOchannel etc. now I'm more confused than ever. There doesn't seem to be any conclusive articles or guides about how to actually achieve this.
There is basically one important rule:
You must call all gtk_* functions from the main thread.
If you update any widgets from another thread, you might get inconsistent results.
Of course, you don't want to wait for TCP data in that thread.
Therefore I would suggest you create a separate thread for doing the communication. In this thread you can wait for data and if you got anything that should affect what you show in your GUI, you can tell the main thread to do the required work.
A simple way to do this is to use g_idle_add() to enqueue a callback function. That callback function is then executed in context of main thread and can update your widgets.
The information what needs to be updated can be stored in some newly allocated memory that is passed to this callback where you have to free it afterwards.

Which thread executes the Registered Action

In the codebehind of my MainPage I register for specific messages like so:
Messenger.Default.Register<String>(this, Notifications.ShowAlert, ShowAlertAction);
As you can imagine the ShowAlertAction does some UI work (pops up a child window in this case)
My concern is that it could happen that a message may be sent from a non-UI thread. When the message is sent is it executed on the thread that does the sending or the thread that did the registering?
The Messenger does not dispatch to a different thread. So this is correct, the action is executed on the sender's thread, which can cause a cross thread exception. To avoid this, the recommended way is to use the DispatcherHelper class to send the message on the main thread even if your sender is running on a background thread.
Some other frameworks do the dispatching automatically (for example Prism) but the API is complex and confusing. I preferred a straightforward approach.
Cheers
Laurent

Dispose called by Component.Finalize() on non-UI thread - does this mean Dispose methods always have to be thread safe?

I checked which thread my Dispose(bool) methods get called on. When the app is running, it is always the UI thread that calls Dispose, say when clicking on the [x] to close a Form. But when I close the whole app, many Dispose methods get called on a (single) different thread. When I dump the stack trace, I see that they all get called from
System.ComponentModel.Component.Finalize().
Does that mean all my Dispose methods need to be made thread-safe? Or is WinForms guaranteeing that the UI thread won't touch these objects any more and does it also establish some kind of "happened-before" relationship between the UI thread and the one that's now finalizing?
Yes, the finalizer works on a separate thread. Usually this is no problem, because when an Object is finalized it is not reachable by any user thread (like the UI thread) anymore. So, you usually do not have to be thread-safe within your finalizer.

WPF Application thread usage going up and up

I have a multithreaded WPF application that is using > 600 threads after is has been running for more than 8 hours. All but approximately 10 of these threads have a stack trace that is very similar to this:
Stack trace 1:
ntkrnlpa.exe!NtInitialUserProcessBuffer+0x7b
ntkrnlpa.exe!MiAddWorkingSetPage+0x174
ntkrnlpa.exe!MiAddWsleHash+0x12a
ntkrnlpa.exe!PopSystemButtonHandler+0x141
ntkrnlpa.exe!KiInterruptTemplate+0x62
ntdll.dll!KiFastSystemCallRet
ntdll.dll!ZwWaitForMultipleObjects+0xc
KERNEL32.dll!WaitForMultipleObjectsEx+0x12c
mscorwks.dll!WaitForMultipleObjectsEx_SO_TOLERANT+0x6f
mscorwks.dll!Thread::DoAppropriateAptStateWait+0x3c
mscorwks.dll!Thread::DoAppropriateWaitWorker+0x13c
mscorwks.dll!Thread::DoAppropriateWait+0x40
mscorwks.dll!WaitHandleNative::CorWaitOneNative+0x156
mscorlib.ni.dll+0x1f68af
mscorlib.ni.dll+0x1caa17
WindowsBase.ni.dll+0x24ac34
WindowsBase.ni.dll+0x2aeb1e
WindowsBase.ni.dll+0x9445d
WindowsBase.ni.dll+0x9267f
mscorwks.dll!JITutil_IsInstanceOfAny+0x106
mscorlib.ni.dll+0x1e842f
mscorwks.dll!CallDescrWorker+0x33
mscorwks.dll!CallDescrWorkerWithHandler+0xa3
mscorwks.dll!MethodDesc::CallDescr+0x19c
mscorwks.dll!MethodDesc::CallTargetWorker+0x1f
mscorwks.dll!MethodDescCallSite::Call+0x1a
mscorwks.dll!ExecuteCodeWithGuaranteedCleanupHelper+0x9f
mscorwks.dll!ReflectionInvocation::ExecuteCodeWithGuaranteedCleanup+0x10f
mscorlib.ni.dll+0x235677
mscorlib.ni.dll+0x2202a5
mscorlib.ni.dll+0x1e839b
mscorwks.dll!CallDescrWorker+0x33
mscorwks.dll!CallDescrWorkerWithHandler+0xa3
mscorwks.dll!DispatchCallBody+0x1e
mscorwks.dll!DispatchCallDebuggerWrapper+0x3d
mscorwks.dll!DispatchCallNoEH+0x51
mscorwks.dll!AddTimerCallback_Worker+0x66
mscorwks.dll!Thread::DoADCallBack+0x32a
mscorwks.dll!Thread::ShouldChangeAbortToUnload+0xe3
mscorwks.dll!Thread::ShouldChangeAbortToUnload+0x30a
mscorwks.dll!Thread::ShouldChangeAbortToUnload+0x33e
mscorwks.dll!ManagedThreadBase::ThreadPool+0x13
mscorwks.dll!AddTimerCallbackEx+0x83
mscorwks.dll!AddTimerCallback+0x10
mscorwks.dll!ThreadpoolMgr::AsyncTimerCallbackCompletion+0x64
mscorwks.dll!UnManagedPerAppDomainTPCount::DispatchWorkItem+0x9a
mscorwks.dll!ThreadpoolMgr::ExecuteWorkRequest+0xaf
mscorwks.dll!ThreadpoolMgr::WorkerThreadStart+0x20b
mscorwks.dll!Thread::intermediateThreadProc+0x49
KERNEL32.dll!BaseThreadStart+0x37
Stack Trace 2:
ntkrnlpa.exe!NtInitialUserProcessBuffer+0x7b
ntkrnlpa.exe!MiAddWorkingSetPage+0x174
ntkrnlpa.exe!MiAddWsleHash+0x12a
ntkrnlpa.exe!PopSystemButtonHandler+0x141
ntkrnlpa.exe!KiInterruptTemplate+0x62
ntdll.dll!KiFastSystemCallRet
ntdll.dll!ZwWaitForMultipleObjects+0xc
KERNEL32.dll!WaitForMultipleObjectsEx+0x12c
mscorwks.dll!WaitForMultipleObjectsEx_SO_TOLERANT+0x6f
mscorwks.dll!Thread::DoAppropriateAptStateWait+0x3c
mscorwks.dll!Thread::DoAppropriateWaitWorker+0x13c
mscorwks.dll!Thread::DoAppropriateWait+0x40
mscorwks.dll!WaitHandleNative::CorWaitOneNative+0x156
mscorlib.ni.dll+0x1f68af
mscorlib.ni.dll+0x1caa17
WindowsBase.ni.dll+0x24ac34
WindowsBase.ni.dll+0x2aeb1e
WindowsBase.ni.dll+0x9445d
WindowsBase.ni.dll+0x9267f
mscorwks.dll!JITutil_IsInstanceOfAny+0x106
mscorlib.ni.dll+0x1e842f
mscorwks.dll!CallDescrWorker+0x33
mscorwks.dll!CallDescrWorkerWithHandler+0xa3
mscorwks.dll!MethodDesc::CallDescr+0x19c
mscorwks.dll!MethodDesc::CallTargetWorker+0x1f
mscorwks.dll!MethodDescCallSite::Call+0x1a
mscorwks.dll!ExecuteCodeWithGuaranteedCleanupHelper+0x9f
mscorwks.dll!ReflectionInvocation::ExecuteCodeWithGuaranteedCleanup+0x10f
mscorlib.ni.dll+0x235677
mscorlib.ni.dll+0x2202a5
mscorlib.ni.dll+0x1e839b
mscorwks.dll!CallDescrWorker+0x33
mscorwks.dll!CallDescrWorkerWithHandler+0xa3
mscorwks.dll!DispatchCallBody+0x1e
mscorwks.dll!DispatchCallDebuggerWrapper+0x3d
mscorwks.dll!DispatchCallNoEH+0x51
mscorwks.dll!AddTimerCallback_Worker+0x66
mscorwks.dll!Thread::DoADCallBack+0x32a
mscorwks.dll!Thread::ShouldChangeAbortToUnload+0xe3
mscorwks.dll!Thread::ShouldChangeAbortToUnload+0x30a
mscorwks.dll!Thread::ShouldChangeAbortToUnload+0x33e
mscorwks.dll!ManagedThreadBase::ThreadPool+0x13
mscorwks.dll!AddTimerCallbackEx+0x83
mscorwks.dll!AddTimerCallback+0x10
mscorwks.dll!ThreadpoolMgr::AsyncTimerCallbackCompletion+0x64
mscorwks.dll!UnManagedPerAppDomainTPCount::DispatchWorkItem+0x9a
mscorwks.dll!ThreadpoolMgr::ExecuteWorkRequest+0xaf
mscorwks.dll!ThreadpoolMgr::WorkerThreadStart+0x20b
mscorwks.dll!Thread::intermediateThreadProc+0x49
KERNEL32.dll!BaseThreadStart+0x37
Application uses System.Threading.Timer to periodically poll for data from several webservices using a WCF client proxy and at any giving time, could be making about 20 of these requests at the same time. Each call to a webservice instantiates a new proxy instance but the client is always closed when a response is received from the webservice.
Application also manipulates with bitmaps for a GIS and this is also done on a periodic interval. No where in code am I explicitly creating threads besides localized usage of the Timer class to poll for data periodically. The GIS does
use the BackgroundWorker but they do limit the thread count.
Anyone have an idea on what is spawning these new threads and why they are not being disposed?
TIA.
Yeah, looks like something you shouldn't ignore. They are the threadpool thread that the Timer class uses to make the callback. They are deadlocked, looks like they are waiting for a method call that's marshaled by COM to complete. There should be another thread in your program, one of the other 10 on which you created the GIS object. That thread is not pumping a message loop, a hard requirement for an STA thread that creates single apartment threaded COM components. Or it is stuck itself, not re-entering the message loop. Getting a managed stack trace ought to make it easier to see where the thread is stuck.
Trying to use threads on a COM object that explicitly doesn't support them (very few do) is pointless. Be sure to create the GIS object on your program's main UI thread. And use a DispatcherTimer. Creating your own STA thread that pumps a message loop can be a solution when the GIS component is taking too much of a hit on your user interface.
Problem was not GIS related but was due to System.Threading.Timer call backs queuing up as they were being called faster than they could be actioned. Problem was further compounded by the fact that timer call back was doing a Dispatcher.Invoke to the main user interface thread to refresh data grids. Dispatcher.Invoke was blocking when main user interface was busy, say when user was panning and zooming on map, and before timer call back got a chance to complete it was invoked again.
Fixed problem by temporarily stopping timer when it starts executing the call back and restarting it again after call back is complete. Also, instead of doing a Dispatcher.Invoke to get my grids updated, I changed it to a Dispatcher.BeginInvoke to avoid blocking.

Threading issue with Dispatcher.Invoke and Dispatcher.BeginInvoke

Acording to my understanding Dispatcher.Invoke and Dispatcher.BeginInvoke executes on UI thread, The only difference is That Invoke is synchronous and BeginInvoke is asynchronous.My problem is when i use this code
EDisc.App.Current.Dispatcher.
Invoke(
DispatcherPriority.Normal, new Action(delegate
{
context = NavigationManager.CurrentPage.DataContext;
}));
Value of context is returned. However with the below code
EDisc.App.Current.Dispatcher.
BeginInvoke(
DispatcherPriority.Normal, new Action(delegate
{
context = NavigationManager.CurrentPage.DataContext;
}));
Context is null and i get an InvalidOperation Exception saying "
The calling thread cannot access this object because a different thread owns it.I am calling this from a WCF service which is executing with UseSynchronizationContext = false .Can anybody explain this behaviour?
Both BeginInvoke and Invoke will end up calling an internal method called BeginInvokeImpl to do the work. The difference is that Invoke then waits for the operation to complete before returning.
And there's one other difference: if you are already on the UI thread and you're using DispatcherPriority.Send Invoke will actually invoke the method directly without going via BeginInvokeImpl, meaning that the operation is processed without going via the message queue. (If you're not using Send then any other messages already queued up with higher property than your operation will get processed first.)
But since you're presumably not on the UI thread here - you're on some WCF callback - that special case won't apply. So Invoke ends up calling into the same underlying implementation as BeginInvoke.
From the information you've provided, I'd have to guess that there's a missing detail somewhere here. The code you've shown should work fine, unless perhaps you have multiple UI threads in your application, and the page that happens to be in CurrentPage belongs to different threads from time to time.
If you do have multiple UI threads, then the approach you're using - pushing everything through the current Application object's dispatcher - isn't going to work, because you'll have multiple dispatchers. You'd need to get the right dispatcher for whichever UI element you're planning to touch.
Incidentally, one way you might accidentally end up with multiple UI threads is if you construct a UI object (e.g. a Page) on some worker thread or callback. Is it possible that you've done that somewhere?

Resources