Threads and Locking Question

  • Hi,

    We are using a third party library that performs tasks
    asynchronously. This is ok most of the time, but on some occasions
    I'd like to be able to wait (not on the main thread) until an
    operation completes,

    The flow basically goes like this:

    [theLibraryObject doOperation:myOperation withCompletionBlock:^(void)
    (ResponseObject* theResponseObject)
      {
    //Completion code
      }];

    (The Block syntax is wrong I know, but I don't have the source code
    in front of me.

    The "doOperation: withCompletionBlock:" method just queues the
    operation and returns. When the operation has finished, it calls the
    completion block.

    I'd like to be able to be able to wait in the method that calls
    doOperation: withCompletionBlock until the completion block is
    called, something like this:

    -(void) doAtomicOperation
    {
    [self.mLibraryObject doOperation:myOperation withCompletionBlock:^
    (void)(ResponseObject* theResponseObject)
      {
    //**
    //**    Signal thread that started the operation
    //**
      SIGNAL
      }];

    //**
    //**    Wait for Signal before continuing
    //**
      WAIT_FOR_SIGNAL

    }

    Is there a way of doing this and if so I'd be really grateful if
    someone could show me the code. I've tried using NSLock and
    NSConditionalLock etc. but can't get it to work!

    Thanks a lot
    All the Best
    Dave
  • Should have added, this is for iOS and doesn't have to run on Mac.
    Hi,

    We are using a third party library that performs tasks
    asynchronously. This is ok most of the time, but on some occasions
    I'd like to be able to wait (not on the main thread) until an
    operation completes,

    The flow basically goes like this:

    [theLibraryObject doOperation:myOperation withCompletionBlock:^(void)
    (ResponseObject* theResponseObject)
      {
    //Completion code
      }];

    (The Block syntax is wrong I know, but I don't have the source code
    in front of me.

    The "doOperation: withCompletionBlock:" method just queues the
    operation and returns. When the operation has finished, it calls the
    completion block.

    I'd like to be able to be able to wait in the method that calls
    doOperation: withCompletionBlock until the completion block is
    called, something like this:

    -(void) doAtomicOperation
    {
    [self.mLibraryObject doOperation:myOperation withCompletionBlock:^
    (void)(ResponseObject* theResponseObject)
      {
    //**
    //**    Signal thread that started the operation
    //**
      SIGNAL
      }];

    //**
    //**    Wait for Signal before continuing
    //**
      WAIT_FOR_SIGNAL

    }

    Is there a way of doing this and if so I'd be really grateful if
    someone could show me the code. I've tried using NSLock and
    NSConditionalLock etc. but can't get it to work!

    Thanks a lot
    All the Best
    Dave
  • On May 10, 2012, at 3:42 PM, Dave wrote:

    > We are using a third party library that performs tasks asynchronously. This is ok most of the time, but on some occasions I'd like to be able to wait (not on the main thread) until an operation completes,

    This is usually an indication of a design problem.

    > Is there a way of doing this and if so I'd be really grateful if someone could show me the code. I've tried using NSLock and NSConditionalLock etc. but can't get it to work!

    NSConditionLock should work.  You create it with a condition which you arbitrarily decide means "unsignaled".  The block locks it (without regard to condition) and then immediately unlocks it in a different condition which you decide means "signaled".  The code that needs to wait just locks it when the condition is signaled, unlocks it, and releases it.

    Alternatively, you can use a dispatch_semaphore or dispatch_group for this.  Here's an implementation using dispatch_group (written in main, not tested):

    -(void) doAtomicOperation
    {
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);
    [self.mLibraryObject doOperation:myOperation withCompletionBlock:^(void)(ResponseObject* theResponseObject)
      {
      // Do work
      dispatch_group_leave(group);
      }];

    //**
    //**    Wait for Signal before continuing
    //**
      dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
      dispatch_release(group);
    }

    Regards,
    Ken
  • On 5/10/12 1:42 PM, Dave wrote:
    > Hi,
    >
    > We are using a third party library that performs tasks asynchronously.
    > This is ok most of the time, but on some occasions I'd like to be able
    > to wait (not on the main thread) until an operation completes,
    >
    > The "doOperation: withCompletionBlock:" method just queues the operation
    > and returns. When the operation has finished, it calls the completion
    > block.
    >
    > I'd like to be able to be able to wait in the method that calls
    > doOperation: withCompletionBlock until the completion block is called,
    > something like this:

    Am I correct in assuming that, given your terminology, you are using an
    NSOperationQueue?  If so, and you have access to the code that's
    actually adding the operation to the NSOperationQueue, you could revise
    it to use -addOperations:waitUntilFinished: (passing YES as the second
    argument).  You could of course write a wrapper around this (e.g.
    -doOperation:withCompletionBlock:waitUntilFinished:).

    If you are actually using dispatch queues, you could use dispatch_sync()
    to perform a blocking dispatch.

    Or are you stuck with the library code (perhaps already compiled) and
    are looking to do this entirely externally?  If so, I see that Ken has
    already replied with a solution there.

    --
    Conrad Shultz

    Synthetiq Solutions
    www.synthetiqsolutions.com
  • Hi Ken,

    Thanks for that I will try it out tomorrow, as an aside, is this ok/
    recommended?

    -(void) someMethod:(NSString*) theParameter
    {
    if ([NSThread isMainThread)
    {
    [self performSelectorInBackground:@selector(someMethod:)
    withObject:self];
    return;
    }

    //  Do work

    }

    Thanks again
    Dave

    On 10 May 2012, at 22:09, Ken Thomases wrote:

    > On May 10, 2012, at 3:42 PM, Dave wrote:
    >
    >> We are using a third party library that performs tasks
    >> asynchronously. This is ok most of the time, but on some occasions
    >> I'd like to be able to wait (not on the main thread) until an
    >> operation completes,
    >
    > This is usually an indication of a design problem.
    >
    >
    >> Is there a way of doing this and if so I'd be really grateful if
    >> someone could show me the code. I've tried using NSLock and
    >> NSConditionalLock etc. but can't get it to work!
    >
    > NSConditionLock should work.  You create it with a condition which
    > you arbitrarily decide means "unsignaled".  The block locks it
    > (without regard to condition) and then immediately unlocks it in a
    > different condition which you decide means "signaled".  The code
    > that needs to wait just locks it when the condition is signaled,
    > unlocks it, and releases it.
    >
    > Alternatively, you can use a dispatch_semaphore or dispatch_group
    > for this.  Here's an implementation using dispatch_group (written
    > in main, not tested):
    >
    >
    > -(void) doAtomicOperation
    > {
    > dispatch_group_t group = dispatch_group_create();
    > dispatch_group_enter(group);
    > [self.mLibraryObject doOperation:myOperation withCompletionBlock:^
    > (void)(ResponseObject* theResponseObject)
    > {
    > // Do work
    > dispatch_group_leave(group);
    > }];
    >
    > //**
    > //**    Wait for Signal before continuing
    > //**
    > dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    > dispatch_release(group);
    > }
    >
    > Regards,
    > Ken
    >
  • On May 10, 2012, at 4:44 PM, Dave wrote:

    > Thanks for that I will try it out tomorrow, as an aside, is this ok/recommended?
    >
    > -(void) someMethod:(NSString*) theParameter
    > {
    > if ([NSThread isMainThread)
    > {
    > [self performSelectorInBackground:@selector(someMethod:) withObject:self];

    Presumably, you mean "withObject:theParameter".

    > return;
    > }
    >
    > //  Do work
    >
    > }

    As to whether it's OK/recommended, that depends.  Why are you doing this?  The caller of that method may be very surprised if it's asynchronous.

    Regards,
    Ken
  • On 10 May 2012, at 22:55, Ken Thomases wrote:
    >
    > As to whether it's OK/recommended, that depends.  Why are you doing
    > this?  The caller of that method may be very surprised if it's
    > asynchronous.
    >

    No the caller is always expecting it to be ASync. It's just that I
    have to use a library that uses a delegate Object/selector passed to
    it and calls it back when the task has finished. This is ok and
    wanted most of the time,but now we have added a whole load of other
    functionality and some of it needs to be run in a certain order
    depending on the responses. Sort of like this

    myResultObjectA = nil
    myResultObjectB = nil
    myResultObjectC = nil
    myResultObjectD = nil
    myResultObjectE = nil

    myResultObjectA = doTaskA
    if (myResultObjectA.someProperty == 0)
    myResultObjectB = doTaskBWithSomePropertiesOf: myResultObjectA
    else if (myResultObjectA.someProperty == 1)
    myResultObjectC = doTaskCWithSomePropertiesOf: myResultObjectA
    else
    ERROR;

    if (myResultObjectB == nil)
    myResultObjectD = doTaskDWithSomePropertiesOf: myResultObjectB
    else
    myResultObjectD = doTaskDWithSomePropertiesOf: myResultObjectC

    myResultObjectE = doTaskDWithSomePropertiesOf: myResultObjectA
    andPropertiesOf: myResultObjectD

    return myResultObjectE

    All the doTask methods are ASync,

    The actual implementation I am working with handles the doTaskXXX
    calls by passing in Delegate Object and a Completion Selector to the
    method. When you try to implement the above in that manner , it
    creates a rats nest of methods which resembles out of control goto's!

    It makes more sense to be able to have all the code in one method.

    Cheers
    Dave
previous month may 2012 next month
MTWTFSS
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
Go to today