ios - How to let a thread A wait until thread B is finished, then continue thread A? -
within thread call asynchronous service, runs in thread b. service calls delegate method once finished. want thread wait until thread b finishes. used nscondition this.
this set (skipped unimportant stuff):
-(void)load { self.somecheckistrue = yes; self.condition = [[nscondition alloc] init]; [self.condition lock]; nslog(@"log1"); service *service = // set service [service request:url delegate:self didfinishselector:@selector(response:)]; while (self.somecheckistrue) [self.condition wait]; nslog(@"log3"); [self.condition unlock]; } -(void)response:(id)data { nslog(@"log2"); [self.condition lock]; self.somecheckistrue = no; // response, doesn't matter here [self.condition signal]; [self.condition unlock]; }
for reason, "log1" printed, neither "log2" nor "log3". assume it's why delegate method response called "service thread", thread b, whereas load called thread a.
i tried semaphore, doesn't work either. here code:
-(void)load { nslog(@"log1"); service *service = // set service self.sema = dispatch_semaphore_create(0); [service request:url delegate:self didfinishselector:@selector(response:)]; dispatch_semaphore_wait(self.sema, dispatch_time_forever); nslog(@"log3"); } -(void)response:(id)data { nslog(@"log2"); // response, doesn't matter here dispatch_semaphore_signal(self.sema); }
how can work?
it seems there couple of issues:
in
nscondition
example,load
doing lock, , won't unlock untilresponse
sets state variable.response
can't possibly because, it's trying lock, (which, nature of locks, block until other thread releases lock).furthermore,
load
initiatingservice
request (whose details haven't shared us), based upon behavior describe (namely, not see "log2"), i'm guessing service request scheduled run on same threadload
. (often if service running on other runloop/queue/thread, you'd see argument during start of service make explicit.) ifload
frozen, waiting signal other thread, service won't commence. you'd have share details of nature ofservice
request comment further on that.in comments, described using
gdataservicegoogle
. in original question, suggested service running on separate thread. when looked @ 1 of sample apps, put breakpoint innsurlconnectiondatadelegate
methods, , getting called on main thread (actually, uses "current" thread, , because sample initiated main thread,nsurlconnectiondatadelegate
calls on main thread). confirms prior point.(by way, that's not @ unusual. lots of
nsurlconnectiondatadelegate
based implementations use main queue network connection. i'm not crazy practice, saves them having create runloop network activity. they're assuming wouldn't block main queue.)but if have lock or semaphore on thread invoked service, prevent
nsurlconnectiondatadelegate
methods ever getting called, ,response
method passeddidfinishselector
never called. deadlock.but, sounds identified problem, initiating service call
nsoperation
result in service's internalnsurlconnectiondatadelegate
calls won't called. that's common problemnsurlconnection
calls background queue, solved either (a) scheduling network connection in dedicated thread own run loop; (b) schedulingnsurlconnection
in[nsrunloop mainrunloop]
; or (c) create own run loop operation. , you've identified because gdataservicegoogle service doesn't expose interface controlling run loop used, you'll have go option (c). it's least elegant solution, given constraints of gdataservicegoogle, may best can do.
you ask:
how can work?
while describe couple of solutions below, critical observation should not using semaphores, locks, or tight while
loops @ all. these represent misconception of correct way handle these asynchronous requests: rather "waiting" service request complete, notified when it's complete (when response
method called). remove of the semaphore, locks, , tight while
loops, , move whatever logic wanted @ "log3" , put inside response
method.
with behind us, considering deadlocks more generically, there couple of observations:
make sure schedule service on thread won't lock. example, you'll see third service-dedicated thread/queue on network service run. or folks schedule network stuff on main thread (which never block), though prefer dedicated thread sort of stuff. or i've seen people put call perform runloop right in
load
routine (but think horrible practice). but, can't haveload
perform blocking wait or other function , have run service on same thread, make sure service running on other thread own runloop.if you're going use locks synchronize access key variables, make sure neither thread holding lock prolonged time without reason. try minimize duration of locks (if any) smallest possible portions of code, i.e. times need update mutually accessed resource, release lock possible. having lock around
dispatch_semaphore_wait
or perpetualwhile
loop problematic.more radically, might ask whether there's possibility refactor code eliminate locks , semaphores altogether. (see eliminating lock-based code in concurrency programming guide.) that's not practical, serial queues (or barriers on concurrent queues) have eliminated many situations used rely upon locks , semaphores.
like said above, believe correct solution move away "wait service finish" model, , rely upon service call response
method when it's done. deadlock issues disappear , code lot more efficient.
Comments
Post a Comment