Hi All! I'm having an issue how to properly and reliably canceling a NSURLConnection scheduled on a secondary thread and would really appreciate help.
The actual issue is that sometimes (not always) sending a message from the main thread - which is basically a higher level cancel message - to the thread where the connection delegates are scheduled will block infinitively. I'm sending the message from the main thread via: [self performSelector:@selector(stopConnectionRunLoop_private) onThread:self.connectionThread withObject:nil waitUntilDone:YES modes:[NSArray arrayWithObject: NSDefaultRunLoopMode]]; Note the 'YES' for parameter waitUntilDone, which will be explained later. The main thread blocks infinitively without invoking the selector's message 'stopConnectionRunLoop_private'. The connection is scheduled in NSDefaultRunLoopMode on the secondary thread, as usual. Stack (partial): ---------------- Thread 1 Queue : (null) (main thread) #0 0x35de454c in __semwait_signal () #1 0x35d90f78 in _pthread_cond_wait () #2 0x35d90918 in pthread_cond_wait () #3 0x3517ed64 in -[NSCondition wait] () #4 0x3516910c in -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:] () Thread 6, Queue : (null) #0 0x35d848d8 in select$DARWIN_EXTSN () #1 0x3755aa3a in __CFSocketManager () #2 0x35de5b4c in _pthread_start () #3 0x35dd77ac in thread_start () Thread 7, Queue : (null) #0 0x35d5b400 in semaphore_wait_trap () #1 0x35d91460 in semaphore_wait () #2 0x35e5f3cc in _dispatch_semaphore_wait_slow () A more detailed explanation: ---------------------------- >From the main thread, I invoke this method: - (void) cancelButtonTapped { [self cancel]; } where self is a controller and the connection delegate. -cancel is implemented as follows: - (void) cancel { [self cancelConnectionWaitUntilDone:YES]; } "WaitUntilDone:YES" is a requirement which should guarantee that all delegate methods have finished and the secondary thread has terminated (note, connection delegates execute on the secondary thread). Otherwise, I would possibly risk a race condition due to accessing ivars from the secondary thread and the main thread. -cancelConnectionWaitUntilDone: is implemented as follows, and yes this seems quite elaborated, but I haven't found an easy way to accomplish this, till now: - (void) cancelConnectionWaitUntilDone:(BOOL)wait { if (self.connection) { NSLog(@"Attempt to cancel the connection ..."); [self.connection cancel]; self.connection = nil; NSLog(@"... cancel returned."); } else { NSLog(@"No connection to cancel"); } [self stopConnectionRunLoopWaitUntilDone:wait]; // here it may block infinitively occasionally } Note: the reason for sending a message to the Run Loop is to cause the Run Loop to exit, which in turn can be utilized to check the flag 'runLoopDone_' which causes the outer loop to exit, and eventually causes the secondary thread to exit. Please see the handling of the Run Loop (code fragment) below: runLoopDone_ = NO; [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; do { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]]; if (runLoopDone_) { NSLog(@"Exit RunLoop."); } } while (!runLoopDone_); - (void) stopConnectionRunLoopWaitUntilDone:(BOOL)wait { NSLog(@"stopConnectionRunLoopWaitUntilDone with thread %@", self.connectionThread); if (self.connectionThread == nil) { return; } [self performSelector:@selector(stopConnectionRunLoop_private) onThread:self.connectionThread withObject:nil waitUntilDone:wait modes:[NSArray arrayWithObject: NSDefaultRunLoopMode]]; } - (void) stopConnectionRunLoop_private { if (self.connection) { NSLog(@"cannot stop Run Loop: connection is still active"); return; } runLoopDone_ = YES; } Log: --- 2012-04-25 08:59:07.488 Test[2165:307] Attempt to cancel the connection ... 2012-04-25 08:59:07.532 Test[2165:307] ... cancel returned. 2012-04-25 08:59:07.697 Test[2165:307] stopConnectionRunLoopWaitUntilDone with thread <NSThread: 0x151de0>{name = (null), num = 14} Thanks for help! Regards Andreas _______________________________________________ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com