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:

  1. in nscondition example, load doing lock, , won't unlock until response sets state variable. response can't possibly because, it's trying lock, (which, nature of locks, block until other thread releases lock).

  2. furthermore, load initiating service request (whose details haven't shared us), based upon behavior describe (namely, not see "log2"), i'm guessing service request scheduled run on same thread load. (often if service running on other runloop/queue/thread, you'd see argument during start of service make explicit.) if load frozen, waiting signal other thread, service won't commence. you'd have share details of nature of service request comment further on that.

  3. in comments, described using gdataservicegoogle. in original question, suggested service running on separate thread. when looked @ 1 of sample apps, put breakpoint in nsurlconnectiondatadelegate 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 passed didfinishselector never called. deadlock.

  4. but, sounds identified problem, initiating service call nsoperation result in service's internal nsurlconnectiondatadelegate calls won't called. that's common problem nsurlconnection calls background queue, solved either (a) scheduling network connection in dedicated thread own run loop; (b) scheduling nsurlconnection 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:

  1. 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 have load perform blocking wait or other function , have run service on same thread, make sure service running on other thread own runloop.

  2. 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 perpetual while loop problematic.

  3. 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

Popular posts from this blog

java - Run a .jar on Heroku -

java - Jtable duplicate Rows -

validation - How to pass paramaters like unix into windows batch file -