GCD with runloops and background refresh of app, iOS7 - multithreading

Maybe I mix too many different technologies together and run in some roadblock; some advise would be much appreciated.
I have an app which connects to several server; each connection with one input and output socket stream. The connection goes to a defined port and is close to telnet protocol. Text input/output. quite simple.
First I have an openStream function as wrapper called from main thread which create a client-specific GDC queue and dispatch the input/output-stream creation within that queue asynchronously:
gcdQueue = dispatch_queue_create([self.client.hostName cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_CONCURRENT);
// possible priorities:
// DISPATCH_QUEUE_PRIORITY_HIGH
// DISPATCH_QUEUE_PRIORITY_DEFAULT
// DISPATCH_QUEUE_PRIORITY_LOW
if (self.runASync)
{
// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
dispatch_async(gcdQueue, ^{
[self openStreamsInternal];
});
}
Code for the technical open of steams
...
//
// in openStreamsInternal()
//
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)self.client.hostName, [self.client.hostPort intValue], &_readStream, &_writeStream);
self.inputStream = (__bridge_transfer NSInputStream *)_readStream;
self.outputStream = (__bridge_transfer NSOutputStream *)_writeStream;
[self.inputStream setDelegate:self];
[self.outputStream setDelegate:self];
self.runLoop = [NSRunLoop currentRunLoop];
[self.inputStream scheduleInRunLoop:self.runLoop forMode:NSDefaultRunLoopMode];
[self.outputStream scheduleInRunLoop:self.runLoop forMode:NSDefaultRunLoopMode];
[self.inputStream open];
[self.outputStream open];
// ... some lines later
if (self.runASync && (self.inputStream || self.outputStream))
{
[self.runLoop run];
}
I open both socket streams and link them to a runloop within the GCD-queue (assuming it will indirectly create a thread; not sure if that is always guaranteed).
Then via the delegate (a member function of my connection class) for the streams in
Code:
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
I do what I have to do with in data flooding in. No issues until I stay in foreground. I close the streams when I go into background to release the resources.
Now with iOS 7 I want to enable background refresh for the streams. For that i don't close the streams anymore when moving into background and have the notification code in
Code:
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(#"called in background for data fetch");
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
for (Connection *connection in self.document.clientList)
{
// Add a task to the group
[connection parseResponseInQueue:group];
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(#"finished with background for data fetch");
completionHandler(UIBackgroundFetchResultNewData);
}
This is one of my variants of background processing; not working well. This one supposed to wait a second and check if the input stream has data copied. If thats the case the parser would be called and the method comes to and end; removing one item from the dispatch group created in the iOS7 background app notification.
I don't like the dispatch_after as it seems very brute; but without I run in an endless loop as the streams seems not be triggered at all times.
Code:
- (void)parseResponseInQueue:(dispatch_group_t)group
{
if (gcdQueue != nil)
{
dispatch_group_async(group, gcdQueue, ^{
while ([self.data length] > 0)
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), gcdQueue, ^{
NSLog(#"%#, wait for parser in background", self.client.hostName);
});
}
#if 0
if ([self.data length] > 0)
{
NSLog(#"%#, start working on buffer %d from background", self.client.hostName, [self.data length]);
[self parseResponse];
NSLog(#"%#, finish working on buffer, left %d in background", self.client.hostName, [self.data length]);
// NSLog(#"data : %#", [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]);
}
else
{
NSLog(#"%#, no data for background processing", self.client.hostName);
}
#endif
});
}
}
But somehow I don't get the refresh done. Sometimes the completionHandler finish without any update and sometime my dispatch group never finish.
So my question is mainly:
1) what is your suggestion to combine background app refresh with multiple streams in GCD queues.
2) does those runloops still be active when I trigger in background
3) are the GCD queues still active
4) should I better schedule in one runloop for all client connection in addition to one main runloop ?
Somehow I need to fresh thoughts on the way forward.
TIA

I have been working on a cross platform real time multiplayer game and ran into similar problems. The core issue I faced was with multiple threads competing for compute cycles and bottlenecks while trying to update common resources. I also had a bunch of scheduled threads that updated my game state.
I ended up switching to a single run loop for all my connections and background scheduled events. That helped in clearly identifying and properly isolating critical sections. This also simplified my control flow. I also saw an increase in performance since there were only 4 threads now that were competing for cycles instead of the earlier 20+
So for your Q4 I recommend that you switch to a single schedule.
For Q1 again, A single combined process for app refresh will not only speed up your app but make it easier to manage and debug.
For Q2 and Q3 It's best if you tested it out on your code by using logs as there may be factors involved that are not apparent in the code you shared.

Related

dataTaskWithURL for dummies

I keep learning iDev but I still can't deal with http requests.
It seems to be crazy, but everybody whom I talk about synchronous requests do not understand me. Okay, it's really important to keep on a background queue as much as it possible to provide smooth UI. But in my case I load JSON data from server and I need to use this data immediately.
The only way I achieved it are semaphores. Is it okay? Or I have to use smth else? I tried NSOperation, but in fact I have to many little requests so creating each class for them for me seems to be not easy-reading-code.
func getUserInfo(userID: Int) -> User {
var user = User()
let linkURL = URL(string: "https://server.com")!
let session = URLSession.shared
let semaphore = DispatchSemaphore(value: 0)
let dataRequest = session.dataTask(with: linkURL) { (data, response, error) in
let json = JSON(data: data!)
user.userName = json["first_name"].stringValue
user.userSurname = json["last_name"].stringValue
semaphore.signal()
}
dataRequest.resume()
semaphore.wait(timeout: DispatchTime.distantFuture)
return user
}
You wrote that people don't understand you, but on the other hand it reveals that you don't understand how asynchronous network requests work.
For example imagine you are setting an alarm for a specific time.
Now you have two options to spend the following time.
Do nothing but sitting in front of the alarm clock and wait until the alarm occurs. Have you ever done that? Certainly not, but this is exactly what you have in mind regarding the network request.
Do several useful things ignoring the alarm clock until it rings. That is the way how asynchronous tasks work.
In terms of a programming language you need a completion handler which is called by the network request when the data has been loaded. In Swift you are using a closure for that purpose.
For convenience declare an enum with associated values for the success and failure cases and use it as the return value in the completion handler
enum RequestResult {
case Success(User), Failure(Error)
}
Add a completion handler to your function including the error case. It is highly recommended to handle always the error parameter of an asynchronous task. When the data task returns it calls the completion closure passing the user or the error depending on the situation.
func getUserInfo(userID: Int, completion:#escaping (RequestResult) -> ()) {
let linkURL = URL(string: "https://server.com")!
let session = URLSession.shared
let dataRequest = session.dataTask(with: linkURL) { (data, response, error) in
if error != nil {
completion(.Failure(error!))
} else {
let json = JSON(data: data!)
var user = User()
user.userName = json["first_name"].stringValue
user.userSurname = json["last_name"].stringValue
completion(.Success(user))
}
}
dataRequest.resume()
}
Now you can call the function with this code:
getUserInfo(userID: 12) { result in
switch result {
case .Success(let user) :
print(user)
// do something with the user
case .Failure(let error) :
print(error)
// handle the error
}
}
In practice the point in time right after your semaphore and the switch result line in the completion block is exactly the same.
Never use semaphores as an alibi not to deal with asynchronous patterns
I hope the alarm clock example clarifies how asynchronous data processing works and why it is much more efficient to get notified (active) rather than waiting (passive).
Don't try to force network connections to work synchronously. It invariably leads to problems. Whatever code is making the above call could potentially be blocked for up to 90 seconds (30 second DNS timeout + 60 second request timeout) waiting for that request to complete or fail. That's an eternity. And if that code is running on your main thread on iOS, the operating system will kill your app outright long before you reach the 90 second mark.
Instead, design your code to handle responses asynchronously. Basically:
Create data structures to hold the results of various requests, such as obtaining info from the user.
Kick off those requests.
When each request comes back, check to see if you have all the data you need to do something, and then do it.
For a really simple example, if you have a method that updates the UI with the logged in user's name, instead of:
[self updateUIWithUserInfo:[self getUserInfoForUser:user]];
you would redesign this as:
[self getUserInfoFromServerAndRun:^(NSDictionary *userInfo) {
[self updateUIWithUserInfo:userInfo];
}];
so that when the response to the request arrives, it performs the UI update action, rather than trying to start a UI update action and having it block waiting for data from the server.
If you need two things—say the userInfo and a list of books that the user has read, you could do:
[self getUserInfoFromServerAndRun:^(NSDictionary *userInfo) {
self.userInfo = userInfo;
[self updateUI];
}];
[self getBookListFromServerAndRun:^(NSDictionary *bookList) {
self.bookList = bookList;
[self updateUI];
}];
...
(void)updateUI
{
if (!self.bookList) return;
if (!self.userInfo) return;
...
}
or whatever. Blocks are your friend here. :-)
Yes, it's a pain to rethink your code to work asynchronously, but the end result is much, much more reliable and yields a much better user experience.

Updating a cocoa interface while processing code in a separate thread, using performSelectorInBackground

I am writing an app that can revert the firmware of a particular device. While executing this revert code, I wish to display a progress indicator.
This problem is of course best tackled with the use of multiple threads (http://stackoverflow.com/questions/1225700/can-i-start-a-thread-by-pressing-a-button-in-a-cocoa-interface-and-keep-using-in).
I have implemented the performSelectorInBackground method, which (according to the documentation) launches the specified selector in a separate thread. Meanwhile, my GUI is updated from the main thread by querying the 'reverter' object.
However, the GUI does not seem to be updating until the code in the secondary thread has finished executing. I obviously need the two to run in parallel. Here is what I've got so far - I'd be really grateful for any help as this is my first time with threading.
-(IBAction)pushButton:(id)sender{
//instatiate reverter object, which does all the firmware processing
Reverter *reverter = [[Reverter alloc] init];
//update the GUI to show a tab with a progress indicator
[tabView selectTabViewItemWithIdentifier:#"RevertProgressTab"];
//process revert code in a separate thread
[reverter performSelectorInBackground:#selector(revertFirmware) withObject:nil];
//process is complete when reverter progress reaches 100
while (!([reverter progress] == 100)) {
//check for failure
if ([reverter hasFailed]) {
[self showRevertFailureTab:nil];
return;
}
//update the progress indicator in the interface
[revertProgressBar setDoubleValue:(double)[reverter progress]];
[NSThread sleepForTimeInterval:0.05];
}
[self showRevertSuccessTab:nil];
}
Have I done anything obvious that would stop the GUI from being updated while the revertFirmware method runs?
Your while loop
while (/*condition*/) {
[NSThread sleepForTimeInterval:x];
}
will prevent your UI from updating. Your UI will only update as soon as your pushButton: method returns.
Instead of polling I would advice you start using an asynchronous event model:
Add a delegate to your reverter object
#protocol ReverterDelegate <NSObject>
- (void) reverterProgressDidUpdate:(float)progress;
#end
#interface Reverter : NSObject {
id<ReverterDelegate> delegate;
}
#property(assign) id<ReverterDelegate> delegate;
#end
Register your controller class as a delegate to your reverter
reverter.delegate = self;
and handle that event
- (void) reverterProgressDidUpdate:(float)progress {
// update ui
}
In your background thread send out events to the main thread
- (void) revertFirmware {
// once in a while send notifications of progress updates
if ([self.delegate respondsToSelector:#selector(reverterProgressDidUpdate:)]) {
[self.delegate performSelectorOnMainThread:#selector(reverterProgressDidUpdate:) withObject:[NSNumber numerWithFloat:progress] waitUntilDone:NO];
}
}
Make sure you retain your reverter somewhere, and release it when it's done working. You are now leaking in your pushButton: method. Also this is just a suggestion towards a better model. Instead of using performSelectorInBackground you could take a look at NSOperation and NSOperationQueue for example.

What's the good way to synchronize calls to a NSView?

I have a view that receives new data from a secondary thread. Every time it does, it should redraw itself. However, it doesn't play nice with the run loop, and after some time (it's non-deterministic), I end up getting <Error>: kCGErrorIllegalArgument: CGSUnionRegionWithRect : Invalid region messages in the console.
I'm not sure what's the right way to synchronize the calls to [view setNeedsDisplay:YES] across threads; can you help me?
To clarify a little, thread B (actually a dispatch queue) gives new contents to a view by calling this:
-(void)setImageBuffer:(unsigned char*)buffer
{
/* image handling stuff; thread-safe */
[self setNeedsDisplay:YES]; // but this is not thread-safe
}
And then thread A, on which runs the run loop, should redisplay the view.
-(void)setImageBuffer:(unsigned char*)buffer
{
/* image handling stuff; thread-safe */
[self performSelectorOnMainThread:#selector(induceRedraw)
withObject:nil
// Don't just copy this; pick one...
waitUntilDone:YES or NO];
}
-(void)induceRedraw
{
[self setNeedsDisplay:YES]; // but this is not thread-safe
}
With GCD you don't need the extra proxy method:
dispatch_queue_t q = dispatch_get_main_queue();
dispatch_async(q, ^(void) {
[self setNeedsDisplay: YES];
});

How can I accomplish ThreadPool.Join?

I am writing a windows service that uses ThreadPool.QueueUserWorkItem(). Each thread is a short-lived task.
When the service is stopped, I need to make sure that all the threads that are currently executing complete. Is there some way of waiting until the queue clears itself?
You could create an event (e.g. ManualResetEvent) in each thread, and keep it in a synchronised list (using the lock construct). Set the event or remove it from the list when the task is finished.
When you want to join, you can use WaitHandle.WaitAll (MSDN documentation) to wait for all the events to be signalled.
It's a hack, but I can't see how to reduce it to anything simpler!
Edit: additionally, you could ensure that no new events get posted, then wait a couple of seconds. If they are indeed short-lived, you'll have no problem. Even simpler, but more hacky.
Finally, if it's just a short amount of time, the service won't exit until all threads have died (unless they are background threads); so if it's a short amount of time, the service control manager won't mind a second or so - you can just leave them to expire - in my experience.
The standard pattern for doing this is to use a counter which holds the number of pending work items and one ManualResetEvent that is signalled when the counter reaches zero. This is generally better than using a WaitHandle for each work item as that does not scale very well when there are a lot of simultaneous work items. Plus, some of the static WaitHandle method only accept a maximum of 64 instances anyway.
// Initialize to 1 because we are going to treat the current thread as
// a work item as well. This is to avoid a race that could occur when
// one work item gets queued and completed before the next work item
// is queued.
int count = 1;
var finished = new ManualResetEvent(false);
try
{
while (...)
{
Interlocked.Increment(ref counter);
ThreadPool.QueueUserWorkItem(
delegate(object state)
{
try
{
// Your task goes here.
}
finally
{
// Decrement the counter to indicate the work item is done.
if (Interlocked.Decrement(ref count) == 0)
{
finished.Set();
}
}
});
}
}
finally
{
// Decrement the counter to indicate the queueing thread is done.
if (Interlocked.Decrement(ref count) == 0)
{
finished.Set();
}
}
finished.WaitOne();

"window procedure" of a newly created thread without window

I want to create a thread for some db writes that should not block the ui in case the db is not there. For synchronizing with the main thread, I'd like to use windows messages. The main thread sends the data to be written to the writer thread.
Sending is no problem, since CreateThread returns the handle of the newly created thread. I thought about creating a standard windows event loop for processing the messages. But how do I get a window procedure as a target for DispatchMessage without a window?
Standard windows event loop (from MSDN):
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Why windows messages? Because they are fast (windows relies on them) and thread-safe. This case is also special as there is no need for the second thread to read any data. It just has to recieve data, write it to the DB and then wait for the next data to arrive. But that's just what the standard event loop does. GetMessage waits for the data, then the data is processed and everything starts again. There's even a defined signal for terminating the thread that is well understood - WM_QUIT.
Other synchronizing constructs block one of the threads every now and then (critical section, semaphore, mutex). As for the events mentioned in the comment - I don't know them.
It might seem contrary to common sense, but for messages that don't have windows, it's actually better to create a hidden window with your window proc than to manually filter the results of GetMessage() in a message pump.
The fact that you have an HWND means that as long as the right thread has a message pump going, the message is going to get routed somewhere. Consider that many functions, even internal Win32 ones, have their own message pumps (for example MessageBox()). And the code for MessageBox() isn't going to know to invoke your custom code after its GetMessage(), unless there's a window handle and window proc that DispatchMessage() will know about.
By creating a hidden window, you're covered by any message pump running in your thread, even if it isn't written by you.
EDIT: but don't just take my word for it, check these articles from Microsoft's Raymond Chen.
Thread messages are eaten by modal loops
Why do messages posted by PostThreadMessage disappear?
Why isn't there a SendThreadMessage function?
NOTE: Refer this code only when you don't need any sort of UI-related or some COM-related code. Other than such corner cases, this code works correctly: especially good for pure computation-bounded worker thread.
DispathMessage and TranslateMessage are not necessary if the thread is not having a window. So, simply just ignore it. HWND is nothing to do with your scenario. You don't actually need to create any Window at all. Note that that two *Message functions are needed to handle Windows-UI-related message such as WM_KEYDOWN and WM_PAINT.
I also prefer Windows Messages to synchronize and communicate between threads by using PostThreadMessage and GetMessage, or PeekMessage. I wanted to cut and paste from my code, but I'll just briefly sketch the idea.
#define WM_MY_THREAD_MESSAGE_X (WM_USER + 100)
#define WM_MY_THREAD_MESSAGE_Y (WM_USER + 100)
// Worker Thread: No Window in this thread
unsigned int CALLBACK WorkerThread(void* data)
{
// Get the master thread's ID
DWORD master_tid = ...;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
if (msg.message == WM_MY_THREAD_MESSAGE_X)
{
// Do your task
// If you want to response,
PostThreadMessage(master_tid, WM_MY_THREAD_MESSAGE_X, ... ...);
}
//...
if (msg.message == WM_QUIT)
break;
}
}
return 0;
}
// In the Master Thread
//
// Spawn the worker thread
CreateThread( ... WorkerThread ... &worker_tid);
// Send message to worker thread
PostThreadMessage(worker_tid, WM_MY_THREAD_MESSAGE_X, ... ...);
// If you want the worker thread to quit
PostQuitMessage(worker_tid);
// If you want to receive message from the worker thread, it's simple
// You just need to write a message handler for WM_MY_THREAD_MESSAGE_X
LRESULT OnMyThreadMessage(WPARAM, LPARAM)
{
...
}
I'm a bit afraid that this is what you wanted. But, the code, I think, is very easy to understand. In general, a thread is created without having message queue. But, once Window-message related function is called, then the message queue for the thread is initialized. Please note that again no Window is necessary to post/receive Window messages.
You don't need a window procedure in your thread unless the thread has actual windows to manage. Once the thread has called Peek/GetMessage(), it already has the same message that a window procedure would receive, and thus can act on it immediately. Dispatching the message is only necessary when actual windows are involved. It is a good idea to dispatch any messages that you do not care about, in case other objects used by your thread have their own windows internally (ActiveX/COM does, for instance). For example:
while( (bRet = GetMessage(&msg, NULL, 0, 0)) != 0 )
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
switch( msg.message )
{
case ...: // process a message
...
break;
case ...: // process a message
...
break;
default: // everything else
TranslateMessage(&msg);
DispatchMessage(&msg);
break;
}
}
}

Resources