Do I understand these concepts correctly? - multithreading

In most of my interviews, I've been asked about web services and multithreading. I've done neither, so I decided to learn more about Web Services and Multithreading using Grand Central Dispatch.
For web services, the way that I understand it is that you need to fetch the data using a class such as NSURLConnection. basically setup a new NSURL, then a connection, then a request. You also need to make use of the API's methods such as didConnect, didReceiveData, and didFailLoadWithError. After you receive the data, which is generally in JSON or XML format and stored as an NSData object, you can store it and parse through it. There are multiple ways to parse through it, such as by using SBJSON or NSXMLParser. You can then do with it what you need.
For multithreading, Grand Central Dispatch is a c-style way of multithreading. Basically, you use it when you need to do heavy hauling away from the main thread to avoid the app freezing. You can dispatch synchronously or asynchronously. Asynchronously means that the method on the main thread will continue executing, synchronously means that it will not. You never need to use GCD alongside with NSURLConnection, because NSURLConnection already does its work in the background then calls upon delegates in the main thread. But, for saving and unzipping files, you should use GCD. When you call dispatch_async, you pass in a dispatch queue. You can use either a serial queue or a concurrent queue. A serial queue will execute tasks in the queue one at a time, in the order that they arrived. It is the default setting. With concurrently queues, tasks executed concurrently might be executed at the same time.
My first question is, do I have a proper understanding of these two concepts? I know that there is a lot to learn about GCD, but I just want to make sure that I have the basic ideas correct. Also, with GCD, why would someone ever want to dispatch synchronously, wouldn't that defeat the purpose of multithreading?

The only reason to dispatch synchronously is to prevent the current code from continuing until the critical section finishes.
For example, if you wanted to get some value from the shared resource and use it right away, you would need to dispatch synchronously. If the current code does not need to wait for the critical section to complete, or if it can simply submit additional follow-up tasks to the same serial queue, submitting asynchronously is generally preferred.

You can make synchronous request and dispatch it by using dispatch_async or dispatch_sync call. It will totally run in background.
-(void)requestSomething:(NSString *)url
{
NSString *queue_id = #"queue_identifier";
dispatch_queue_t queue = dispatch_queue_create([queue_id UTF8String], 0);
dispatch_queue_t main = dispatch_get_main_queue();
dispatch_async(queue, ^{
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
NSError *serviceError = nil;
NSURLResponse *serviceResponse = nil;
NSData *dataResponse = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&serviceResponse error:&serviceError];
if(serviceError)
{
dispatch_sync(main, ^{
// Do UI work like removing indicator or show user an alert with description of error using serviceError object.
return;
});
}
else
{
// Use dataResponse object and parse it as this part of code will not executed on main thread.
dispatch_sync(main, ^{
// Do UI work like updating table-view or labels using parsed data or removing indicator
});
}
});
// If your project is not developed under ARC mechanism, add following line
dispatch_release(queue);
}

Related

GCD dispatch_sync priority over previously queued dispatch_async

I have a class that wraps a data model and is accessed/modified by multiple threads. I need to make sure modification to data model is synchronized. I am using a dispatch_queue_create(..., DISPATCH_QUEUE_SERIAL). This is working really well for my needs.
Most of the methods on my class internally call "dispatch_async(queue, ^{...});". There are a few places where I need to return a snapshot result. This is a simplified example of how that looks:
- (NSArray*) getSomeData {
__block NSArray* result = nil;
dispatch_sync(queue, ^{
... Do Stuff ...
result = blah.blah;
}
return result;
}
Now, lets assume that 5 "async tasks" are queued and one is currently executing. Now a "sync" task is scheduled. When will the "sync task" execute?
What I would like to have happen is "sync task" is executed ahead of any pending "async tasks". Is this what happens by default? If not is there a way to priority queue the "sync task"?
BTW,
I know I can set an overall queue priority but that is not what this question is about. For me queue priority normal is just fine. I just want my synchronous tasks to happen before any pending asynchronous tasks.
There's not a generic setting for "perform sync tasks first" or for setting relative priority between enqueued blocks in a single queue. To recap what may be obvious, a serial queue is going to work like a queue: first in, first out. That said, it's pretty easy to conceive of how you might achieve this effect using multiple queues and targeting. For example:
realQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
asyncOpsQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(asyncOpsQueue, realQueue);
for (NSUInteger i = 0; i < 10; i++)
{
dispatch_async(asyncOpsQueue, ^{
NSLog(#"Doing async work block %#", #(i));
sleep(1);
});
}
// Then whenever you have high priority sync work to do, stop the async
// queue, do your work, and then restart it.
dispatch_suspend(asyncOpsQueue);
dispatch_sync(realQueue, ^{
NSLog(#"Doing sync work block");
});
dispatch_resume(asyncOpsQueue);
One thing to know is that an executing block effectively can't be canceled/suspended/terminated (from the outside) once it's begun. So any async enqueued block that's in flight has to run to completion before your sync block can start, but this arrangement of targeting allows you to pause the flow of async blocks and inject your sync block. Note that it also doesn't matter that you're doing a sync block. It could, just as easily, be an async block of high priority, but in that case you would probably want to move the dispatch_resume into the block itself.

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.

Passing a `Disposable` object safely to the UI thread with TPL

We recently adopted the TPL as the toolkit for running some heavy background tasks.
These tasks typically produce a single object that implements IDisposable. This is because it has some OS handles internally.
What I want to happen is that the object produced by the background thread will be properly disposed at all times, also when the handover coincides with application shutdown.
After some thinking, I wrote this:
private void RunOnUiThread(Object data, Action<Object> action)
{
var t = Task.Factory.StartNew(action, data, CancellationToken.None, TaskCreationOptions.None, _uiThreadScheduler);
t.ContinueWith(delegate(Task task)
{
if (!task.IsCompleted)
{
DisposableObject.DisposeObject(task.AsyncState);
}
});
}
The background Task calls RunOnUiThread to pass its result to the UI thread. The task t is scheduled on the UI thread, and takes ownership of the data passed in. I was expecting that if t could not be executed because the ui thread's message pump was shut down, the continuation would run, and I could see that that the task had failed, and dispose the object myself. DisposeObject() is a helper that checks if the object is actually IDisposable, and non-null, prior to disposing it.
Sadly, it does not work. If I close the application after the background task t is created, the continuation is not executed.
I solved this problem before. At that time I was using the Threadpool and the WPF Dispatcher to post messages on the UI thread. It wasn't very pretty, but in the end it worked. I was hoping that the TPL was better at this scenario. It would even be better if I could somehow teach the TPL that it should Dispose all leftover AsyncState objects if they implement IDisposable.
So, the code is mainly to illustrate the problem. I want to learn about any solution that allows me to safely handover Disposable objects to the UI thread from background Tasks, and preferably one with as little code as possible.
When a process closes, all of it's kernel handles are automatically closed. You shouldn't need to worry about this:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686722(v=vs.85).aspx
Have a look at the RX library. This may allow you to do what you want.
From MSDN:
IsCompleted will return true when the Task is in one of the three
final states: RanToCompletion, Faulted, or Canceled
In other words, your DisposableObject.DisposeObject will never be called, because the continuation will always be scheduled after one of the above conditions has taken place. I believe what you meant to do was :
t.ContinueWith(t => DisposableObject.DisposeObject(task.AsyncState),
TaskContinuationOptions.NotOnRanToCompletion)
(BTW you could have simply captured the data variable rather than using the AsyncState property)
However I wouldn't use a continuation for something that you want to ensure happens at all times. I believe a try-finally block will be more fitting here:
private void RunOnUiThread2(Object data, Action<Object> action)
{
var t = Task.Factory.StartNew(() =>
{
try
{
action(data);
}
finally
{
DisposableObject.DisposeObject(task.AsyncState);
//Or use a new *foreground* thread if the disposing is heavy
}
}, CancellationToken.None, TaskCreationOptions.None, _uiThreadScheduler);
}

Writing to Core Data from a secondary thread

I have an HTTP call to a URL, which returns my data in JSON format, I parse it, then I have to load it in my Core Data context.
Now I am doing it (parsing - entities creation - commit) on the main thread, by using GCD (grand central dispatch) to dispatch a block on the main queue.
The http call is asynchronous, so it's ok, but the db loading is not, so it freezes my user interface: a UITableView backed by a NSFetchedResultsController.
What I'd like to do, is making these last tasks on a secondary thread, but don't know how!
I heard something about creating a second context, using that on the secondary thread, then trash it and "refresh" the "main" context, don't know how to explain.
Maybe is there a wwdc ed. video on this argument, too? I can't find valid documentation.
Can you help me, loading data in asynchronous way, so my table never stop scrolling?
There is a rule: One context for one thread. Create new context in your not main queue and work with it.
Add observer for this context:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(<#Selector name#>)
name:NSManagedObjectContextDidSaveNotification
object:<#A managed object context#>];
After your parser is done and objects in context, save that context which will kick out notification. In main queue, catch this notification and on main queue context call - (void)mergeChangesFromContextDidSaveNotification:(NSNotification *)notification.

NSFetchedResultsController performFetch on background thread

I have to perform a fetch via NSFetchedResultsController on a background thread.
My current solution is structured like that:
dispatch_queue_t fetchQueue = dispatch_queue_create("backgroundfetching", NULL);
dispatch_async(fetchQueue,^{
// 1. Create NSManagedObjectContext
// 2. Create NSFetchRequest
// 3. Create NSFetchedResultsController
// 4. PerformFetch
dispatch_async(dispatch_get_main_queue(),^{
[[self table] reloadData];
});
});
dispatch_release(fetchQueue);
My first tests ran well but is that the appropriate way?
Since the fetched results controller is intended to control the data that defines a tableview, it belongs on the foreground thread/operation that the UI runs on. It's rather pointless to put it on a background thread as you would lose all the advantages of using it in the first place.
I would also be concerned about the effects of sending the FRC delegate messages across asynchronous threads. I'm not sure how reliable that would be.
Having said all that, the sketch of your implementation looks fine as far as it goes.
I believe there is something fundamentally wrong with this approach, as you're sharing managed objects across threads (you're fetching objects on one thread and referencing them on your main thread). In practice it will work, but will sometimes lead to crashes. Because Apple makes it clear that the only ways to share managed objects across threads is using the objectWithID: method or the MOCDidSave notifications.
From the Core Data Programming Guide:
You fetch in one managed object context on a background thread, and
pass the object IDs of the fetched objects to another thread. In the
second thread (typically the application's main thread, so that you
can then display the results), you use the second context to fault in
objects with those object IDs (you use objectWithID: to instantiate
the object).

Resources