Update GUI from worker thread works (WinForms), why? - multithreading

WinForms (VS2015 / .NET 4.6)
In my background thread
System.Threading.Tasks.Task.Run(() =>
{
...
_callback?.Progress("abcd");
...
});
I call the GUI (_callback), which implements an interface in the Form class.
Here, I modify textbox, progressbar, etc values.
void IWorkerCallback.Log(string message)
{
_textBoxLog.AppendText($"{message}{Environment.NewLine}");
++_progressBar.Value;
.... etc...
}
And all works fine!
If I break in with debugger, I could see that the Form.IWorkerCallback.Log() function is executed in the worker thread context (in Threads debug window).
It's said everywhere that you MUST change GUI items only on the GUI thread (where they are created), otherwise you get System.InvalidOperationException exception with cross-thread operation not valid.....
But it works fine for me.
Could you explain, why?
Thanks

Running UI calls from another thread is undefined behavior. It may work or not. To get consistent failure on cross-thread calls set Control.CheckForIllegalCrossThreadCalls = true; in the beginning of the program:
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.checkforillegalcrossthreadcalls?view=netframework-4.8
From MSDN documentation:
When a thread other than the creating thread of a control tries to access one of that control's methods or properties, it often leads to unpredictable results. A common invalid thread activity is a call on the wrong thread that accesses the control's Handle property. Set CheckForIllegalCrossThreadCalls to true to find and diagnose this thread activity more easily.
On low Windows API level, cross-thread UI calls that don't use thread local storage or any other thread-specific resources, may be executed successfully. However, we still have thread synchronization problem, so result is also undefined.

Related

Thread safety in Unity

In Unity, the thread cannot operate the object provided by UnityEngine like transform.position etc, which caused an exception that get_transform can only be called from the main thread.
However, these methods can be used in some async function like BeginReceive, so is there anyone can tell me why? The async function is not thread or sth else?
I try the code below:
void Start(){
AsyncCallback callback = new AsyncCallback (demo);
callback.BeginInvoke (null, null, null);
}
void demo(IAsyncResult result){
Debug.Log(Thread.CurrentThread.ManagedThreadId);
Debug.Log(gb.transform.position.ToString());
}
It does throw an exception when I run the code on Unity Editor. However, when I run this code on an Android phone directly, it didn't throw any exception and the code was performed correctly.
The log in applogcat shows that:
Line 13497: 02-20 14:37:49.973 31027 31697 I Unity : 3
Line 13501: 02-20 14:37:49.975 31027 31697 I Unity : (0.0, 0.0, 0.0)
So it seems that the function runs on another thread instead of main thread, so could anyone tell me why transform works on this situation?
Unity doesn't allow calling most API functions from threads other than the main thread, period. All of the event/message processing is actually done on the main thread.
The coroutine system based on IEnumerator is a bit of a hack and doesn't actually allow for multi-threading (keep in mind that even the .NET 4.5 async/await feature doesn't necessarily imply multithreaded execution either).
If calling the UnityEngine API works, you're on the main thread.
UI APIs aren't allowed to be called from a different thread than the UI one.
This simplifies how Unity works behind the scenes and actually makes it faster.
Some async methods are dispatched using an event loop and not a different thread. Just because a method is async it doesn't mean it gets to run on a different thread.
The most obvious example of this in Unity are Coroutines. They do run async, but on the main thread. This is possible because Unity adds all of to a list and executes them every frame.
You can call the Unity API from other threads, but NOT if you're running the game from within the Unity Editor. Release builds do not check which thread the call to the Unity API originated from. I assume they don't bother to avoid the performance hit.
I haven't tested this much myself though. The Unity documentation is quite clear that the API is not thread-safe. Therefore, definitely don't make any property assignments or calls that change the game state from other threads. Merely reading values might be OK, but it depends on the unknown internal caching behavior of UnityEngine, ie. hashtables/dictionaries would be bad for multi-threading.

Boost asio with Qt

I am trying to use boost::asio async client example with a simple Qt GUI like:
A little snippet from my app:
The button click SLOT:
void RestWidget::restGetCall()
{
networkService ntwkSer("www.boost.org","80");
connect(&ntwkSer, SIGNAL(responseReady(std::string)), this, SLOT(showResponse(std::string)));
ntwkSer.get("/LICENSE_1_0.txt");
}
The networkService class is just a wrapper of the above linked boost sample code.Its derived from QObject class for signal,slot mechanism.
void networkService::get(const std::string & path)
{
// boost::thread (boost::bind(&networkService::networkCall,this,path));//this gives me sigabrt
networkCall(path);//this works fine, and i get output as pictured above.
}
void networkService::networkCall(const std::string path)
{
tcp::resolver::query query(host_, port_);//also these host,port fields come out to be invalid/garbage.
//tcp::resolver::query query("www.boost.org","80");//still doesnt resolve the SIGABRT
resolver_.async_resolve(query,
boost::bind(&networkService::handle_resolve, this,
boost::asio::placeholders::error,
boost::asio::placeholders::iterator,
path));
io_service.run();
}
The problem, is when i run the io_service.run() from the boost::thread. i get SIGABRT.
also he host_,port_ networkService wrapper class fields inside the networkService::networkCall(path) function on debugging come out to be invalid, which get saved while constructing:
networkService ntwkSer("www.boost.org","80");
The obvious reason for boost::thread is to make GUI non-blocking,since io_service() has its own eventloop. My intention is to run boost::asio async calls in a seperate boost thread, and notify the GUI thread with QT's Q_OBJECT signal slot mechanism.
I don't get the reason of SIGABRT and also why could the field values of host_ and port_ become invalid once i start using boost::thread.
PS: This same setup, behaves correctly with boost::thread from a similar commandline application (no Qt GUI code), i.e when the networkService class is not hacked for Qt signal/slot to notify the main GUI thread. Here, i use the boost::asio's response from within the boost::thread.
Edit:
as per responses to my question, i tried this... i disabled Q_OBJECT signal/slot and QObject derivation of the networkservice class, to be sure MOC isnt messing things up.. but still, the issue prevails, i get access violation on windows vs sigabrt on linux. The issue of the networkservice object's fields getting corrupted is also present, eventually getting access violation.
In effect no change in behaviour.
before launching thread:
from inside thread
access violation on continue...
So, even without MOC , the issue is still there.
Edit 2:
Im sorry for bothering.. i did a huge mistake, of using a local networkService object from within the boost::thread, which got scoped out when the thread actually ran!
It's difficult to get the asio io_service.run() function to "play well" with the Qt event loop.
It's easier to use a Qt slot that calls io_service::poll() or io_service::poll_one() and then connect that slot to a QTimerEvent.
And it's even easier to use QNetworkAccessManager instead of asio see Qt Client Example
The problem is that with qt only one thread is allowed to manipulate the gui in qt. That is the one calling QApplication::exec. This is done to remove complexity for the users of qt and due to that QApplication / message loop being a singleton. That being said there is some magic going on in qt with threads. All QObjects are assigned a thread. By default the one on which they are created. When a signal slot connection is made it is determined how to actually dispatch the call. If the objects belong to the same thread a signal is dispatched by directly / synchronous invoking the slot. If the objects are assigned to distinguished threads a message is send from one thread to another to invoke the slot on the thread that is assigned to the object where the slot lives. This is what you actually need here.
The problem with your code is that both of your QObjects are created on the same thread. They are therefore assigned the same thread. So the slot which manipulates the GUI is called directly from your worker thread and remember this is prohibited! Since your worker is not the one calling QApplication::exec. To override the automatics and convince to correctly do the thread switch when calling the slot you must use Qt::QueuedConnection when doing the connect.
connect(&ntwkSer, SIGNAL(responseReady(std::string)), this, SLOT(showResponse(std::string)), Qt::QueuedConnection);

NSURLSession dataTaskWithURL

I am using NSURLSession dataTaskWithURL:completionHandler. It looks like completionHandler is executed in a thread which is different than the thread(in my case, it's the main thread) which calls dataTaskWithURL. So my question is, since it is asynchronized, is it possible that the main thread exit, but the completionHandler thread is still running since the response has not come back, which is the case I am trying to avoid. If this could happen, how should I solve the problem? BTW, I am building this as a framework, not an application.Thanks.
In the first part of your question you seem un-sure that the completion handler is running on a different thread. To confirm this let's look at the NSURLSession Class Reference. If we look at the "Creating a Session" section we can see in the description for the following method the answer.
+ sessionWithConfiguration:delegate:delegateQueue:
Swift
init(configuration configuration: NSURLSessionConfiguration,
delegate delegate: NSURLSessionDelegate?,
delegateQueue queue: NSOperationQueue?)
Objective-C
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration
delegate:(id<NSURLSessionDelegate>)delegate
delegateQueue:(NSOperationQueue *)queue
In the parameters table for the NSOperationQueue queue parameter is the following quote.
An operation queue for scheduling the delegate calls and completion handlers. The queue need not be a serial queue. If nil, the session creates a serial operation queue for performing all delegate method calls and completion handler calls.
So we can see the default behavior is to provide a queue whether from the developer or as the default class behavior. Again we can see this in the comments for the method + sessionWithConfiguration:
Discussion
Calling this method is equivalent to calling
sessionWithConfiguration:delegate:delegateQueue: with a nil delegate
and queue.
If you would like a more information you should read Apple's Concurrency Programming Guide. This is also useful in understanding Apple's approach to threading in general.
So the completion handler from - dataTaskWithURL:completionHandler: is running on a different queue, with queues normally providing their own thread(s). This leads the main component of your question. Can the main thread exit, while the completion handler is still running?
The concise answer is no, but why?
To answer this answer this we again turn to Apple's documentation, to a document that everyone should read early in their app developer career!
The App Programming Guide
The Main Run Loop
An app’s main run loop processes all user-related events. The
UIApplication object sets up the main run loop at launch time and uses
it to process events and handle updates to view-based interfaces. As
the name suggests, the main run loop executes on the app’s main
thread. This behavior ensures that user-related events are processed
serially in the order in which they were received.
All of the user interact happens on the main thread - no main thread, no main run loop, no app! So the possible condition you question mentions should never exist!
Apple seems more concerned with you doing background work on the main thread. Checkout the section "Move Work off the Main Thread"...
Be sure to limit the type of work you do on the main thread of your
app. The main thread is where your app handles touch events and other
user input. To ensure that your app is always responsive to the user,
you should never use the main thread to perform long-running or
potentially unbounded tasks, such as tasks that access the network.
Instead, you should always move those tasks onto background threads.
The preferred way to do so is to use Grand Central Dispatch (GCD) or
NSOperation objects to perform tasks asynchronously.
I know this answer is long winded, but I felt the need to offer insight and detail in answering your question - "the why" is just as important and it was good review :)
NSURLSessionTasks always run in background by default that's why we have completion handler which can be used when we get response from Web service.
If you don't get any response explore your request URL and whether HTTPHeaderFields are set properly.
Paste your code so that we can help it
I just asked the same question. Then figured out the answer. The thread of the completion handler is setup in the init of the NSURLSession.
From the documentation:
init(configuration configuration: NSURLSessionConfiguration,
delegate delegate: NSURLSessionDelegate?,
delegateQueue queue: NSOperationQueue?)`
queue - A queue for scheduling the delegate calls and completion handlers. If nil, the session creates a serial operation queue for performing all delegate method calls and completion handler calls.*
My code that sets up for completion on main thread:
var session = NSURLSession(configuration: configuration, delegate:nil, delegateQueue:NSOperationQueue.mainQueue())
(Shown in Swift, Objective-C the same) Maybe post more code if this does not solve.

In Silverlight UI thread, when doing InvokeAsync what happens?

I am trying to solve SL performance issues.
Up until now I had WCF calls which were executed by InvokeAsync.
Now, I changed it to use the BackgroundWorker.
Performance is greatly improved.
what can cause this? what does InvokeAsync did exactly that affected the UI thread? is it opening another UI thread?
Thanks
It comes down to Synchronization contexts. A thread may be associated with SynchronizationContext such as the DispatcherSynchronizationContext (which is the context of the UI thread and only contains this one thread). WCF will complete an operation in the same Synchronization context that it began in, if there is no synchronization context associated with the thread it will use any thread in the thread pool.
Hence if you have several outstanding async operations all invoked from the UI Thread then all those operations will want to run their completion code in the UI Thread. If a number of them complete at the same time the completion code will have to queue up waiting to be dispatched into this single UI thread.
Whereas when you invoke async operations in a Background worker its running in a thread from the thread pool and does not have special synchronisation context. When those operations complete their completion code may run on any available thread in the pool (of which there are several). So near simultaneous completions can all run in parallel on different threads.
In WPF and Silverlight i recommend to use SynchronazationContext to save the main thread, all other thread will use this instance of SynchronazationContext to access the main thread (UI). You use it in this manner (Note: i generated a method that do this and all other methods will access this method to update the UI):
SynchronazationContext ctx = null;
void DoSomething()
{
ctx = SynchronazationContext.Current;
//Some algorithm here
this.UpdatePic("Success !");
}
void ThreadProc()
{
SendOrPostCallback callBack = new SendOrPostCallback(UpdatePic);
ctx.Post(callBack, String.Format("Put here the pic path");
}
void UpdatePic(string _text)
{
//This method run under the main method
}
In .NET 5.0 you can call this complicated functions by mark the method as async and write 'await' when you call the synchronous method - that make the synchronous method as asynchronous method and update the UI with the main thread.

How do you call the GUI thread in Silverlight from the BackgroundWorker method?

I am using a BackgroundWorker thread to do some work outside of the GUI thread in Silverlight 4. I would like to update widgets in the GUI context from the background thread, but have read warnings about doing so from Microsoft documentation. I understand that communicating from one thread to another throws an exception as only the GUI thread can update widgets, but isn't BeginInvoke provided for this:
// BackgroundWorker thread code...
Widget.Dispatcher.BeginInvoke(() => Status.Text = "Hello");
However, I am getting some unpredictable results in my worker code.
What is the proper way to cross communicate with the GUI thread ? Is it by passing a results collection out of the RunWorkerCompleted method ?
Thanks,
Scott
You don't call the GUI code directly.
You must fire and event to which the UI thread subscribes. It then does the marshalling necessary to update the UI safely.
There are plenty of questions (and answers) on this. See some of the "Related" questions in the right hand side bar.

Resources