Error Log says:
bool _WebTryThreadLock(bool), 0x3c689f0: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
App structure:
worker threads are detached from the MainThread as new data is needed via user interaction, each worker thread feeds data into its own slot in an array. The problem arises only when I use the NavigationController to go "back" to the previous view WHILE a thread is still gathering data. I've tried to send a [NSThread exit] to each thread upon viewWillDisappear thats not going to work...
Any suggestions on thread clean-up upon poppin' the view controller?
So apparently i needed to build in checks to the runloop as well as the didRecieveData loop to watch for a global variable to indicate if the view has disappeared. This in turn needs to toggle the global var, causing all open threads to cancel the connection as well as exit the thread.
Related
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.
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.
I have a form that is responsible for creating and setting up an instance of an object, and then telling the object to go do its work. The process is a long one, so there's an area on the form where status messages appears to let the user know something is happening. Messages are set with a setMessage(string msg) function. To allow the form to remain responsive to events, I create a new thread for the object to run in, and pass it the setMessage function as a delegate to allow the object to set status messages on the form. This part is working properly. The main form is responsive and messages posted to its setMessage function appear as expected.
Because the process is a long one, and is made up of many steps, I want to allow the user to terminate the process before it's finished. To do this I created a volatile bool called _stopRequested and a function called shouldStop() that returns its value. This is also given to the object as a delegate. The object can tell if it should terminate by checking shouldStop() periodically, and if it's true, shut down gracefully.
Lastly, Windows controls are not thread safe, so the compiler will complain if a thread other than the one that created the control tries to manipulate it. Therefore, the setMessage function is wrapped in an if statement that tests for this and invokes the function using the parent thread if it's being called from the worker thread (see http://msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx for a description).
The problem arises when the user requests a shutdown. The main form sets _stopRequested to true and then waits for the child thread to finish before closing the application. It does this by executing _child.Join(). Now the parent thread (the one running the form) is in a Join state and can't do anything. The child thread (running the long process) detects the stop flag and attempts to shut down, but before it does, it posts a status message by calling it's setMessage delegate. That delegate points back to the main form, which figures out that the thread setting the message (child) is different than the thread that created the control (parent) and invokes the function in the parent thread. The parent thread is, of course, in a Join state and won't set the text on the text box until the child thread terminates. The child thread won't terminate because it's waiting for the delegate it called to return. Instant deadlock.
I've found examples of signaling a thread to terminate, and I've found examples of child threads sending messages to the parent thread, but I can't find any examples of both things happening at the same time. Can someone give me some pointers on how to avoid this deadlock? Specifically, I'd like the form to wait until the child thread terminates before closing the application but remain able to do work while it waits.
Thanks in advance for the advice.
1-(lazy) Dispatch the method from a new Thread so it doesn't lock
2-(re-think) The main UI thread should be able to control the child thread, so forget the _stopRequested and shouldStop() and implement a childThread.Abort() , abort does not kill the thread, but sends a ThreadAbortException
which can be handled or even canceled
catch(ThreadAbortException e)
{
ReleaseResources();
}
Make the ReleaseResources safe by making various checks such as:
resource != null
or
resource.IsClosed()
The ReleaseResources should be called normally without abort and also by abort.
3-(if possible)stop the child, via main thread call ReleaseResources()
You may have to implement a mix of these.
I have created a Single Dialog application which basically does a series of complex calculation. The application was first created as a Win32 console application and later I decided to add a progressbar and then I converted the console application to a Single Dialog based application. The dialog has a progressbar on it. in OnInitDialog() function of the dialog, I start the calculations. The calculations are running on a worker thread. This thread is created by calling _beginthreadex function. The progressbar is updated by the thread by posting messages to the Dialog by using PostMessage. After the thread has completed execution, I call CDialog::OnOK() function to close the dialog. The issue is that, even after the dialog is closed, the application is not end immediately. It takes nearly 2 seconds to close the application even though the dialog is closed.
Any help to solve this issue is highly appreciated.
Thanks.
It's because your worker thread is still running. The application will not terminate until all threads are finished running. Since your UI thread closes before the worker thread, the window may be hidden, but the process does not terminate until the worker thread has completed its work.
The worker thread might be still running. To make sure that the thread is stopped use events to signal . you can signal an event to kill the thread when the user presses close button in the dialog.
You can check whether the event is signaled inside your complex calculation (may be a loop) and break from it. Thus stopping the thread without any issues.
while(true)
{
//Some complex task
DWORD dwWaitResult;
dwWaitResult = WaitForSingleObject(hwndShutdownEvent,0);
if (WAIT_OBJECT_0 == dwWaitResult)
{
break;
}
}
I use TIdHTTP component to load xml data from a bank in a seperate thread but my form is getting freezed during that time...
what could be the problem ?
I have a main form and thread class, in thread class i have a method called loadData and on thread::Execute i Synchronize(loadData);
when button gets clicked I created the instance of thread class like testThread *t=new testThread(false);
and that's all
when i click the button the main form freezes?
even seperate thread didn't help????
Please help!!!
Synchronize() is running your loadData() method in the context of the main thread, not in the context of your worker thread. That is why your main thread blocks while loadData() is busy. You are misusing Synchronize(), rendering your thread useless. You need to do the bulk of your thread work outside of Synchronize(), and then use Synchronize() only to perform small updates in the main thread when needed, like displaying status (even then, Synchronize() is not always the best choice for that).