Re: waiting for async callback in main thread
Re: waiting for async callback in main thread
- Subject: Re: waiting for async callback in main thread
- From: John Engelhart <email@hidden>
- Date: Tue, 27 Oct 2009 23:53:51 -0400
On Tue, Oct 27, 2009 at 7:37 PM, Jean-Daniel Dupas
<email@hidden>wrote:
>
> Le 27 oct. 2009 à 21:47, Alexander Cohen a écrit :
>
>
>
>> On Oct 27, 2009, at 3:42 PM, Jens Alfke wrote:
>>
>>
>>> On Oct 27, 2009, at 12:11 PM, Alexander Cohen wrote:
>>>
>>> 100% agree with you, and that's what i would normally do. But
>>>> unfortunately, this time i must wait in the mainthread for the callback. I
>>>> know it's wrong, but this time i've gotta do it.
>>>>
>>>
>>> Then use a while loop to run the runloop until your callback's been
>>> invoked. The reason this is described as wrong is because it blocks the main
>>> thread; but if you have to block the main thread, this is the way to do it.
>>>
>>
>> Excellent. I remember reading somewhere that because of changes in 10.6 to
>> the way the runLoop works, it was a bad idea to do this. But for now its
>> working and until someone tells me otherwise, this'll do.
>>
>> thx
>>
>
> According to the CFRunLoop reference (CFRunLoopRun() discussion to be
> exact), it is perfectly valid to call a runloop recursively.
>
> «Run loops can be run recursively. You can call CFRunLoopRun from within
> any run loop callout and create nested run loop activations on the current
> thread’s call stack.»
>
> If you encounter any issue with this function (but look like it's not the
> case), fill a radar.
I would *STRONGLY* advise against doing this. While it may be perfectly safe
to recursively run a CFRunLoop, this says nothing about the implications of
doing so. At first glance, it would seem that everything a run loop "does"
as a result of 'running' needs to be safe to call recursively as well. This
condition is much harder to satisfy, and virtually guaranteed not hold true
for code that gets executed by the main threads run loop.
For example, if anything in the call stack between the last CFRunLoopRun()
and the CFRunLoopRun() you're about to perform has grabbed a lock, the next
run will likely cause a deadlock (except for the obvious case of a recursive
lock). Another potential problem is that "things may appear to happen out
of order temporally". It's not uncommon to program in such a way that the
only way "things happen" is if you directly "make them happen." When you
recursively run the run loop, the chance exists that 'something', possibly
the 'same something', will happen that causes you to end up at the exact
same point, and thus recursively run the run loop again. There is often an
implicit assumption that "nothing can happen until this blocking function
call returns", yet under these circumstances, the top most call on the stack
will complete "before" the one below it, potentially violating an unstated,
but required, temporal ordering assumption. This can lead to subtle, hard
to track down bugs.
While many problems can be elegantly solved using recursion, most can not.
At a minimum, whatever is recursively running the run loop needs to
be reentrant
safe. This is rarely the case, and very difficult to do in practice except
for the most trivial cases. Depending on whats being done, reentrant safe
programming may be more difficult than even multi-threaded programming, on
the order of lockless programming with concurrent mutators.
In fact, reading over the OP's description of the problem, recursively
running the run loop this way is probably going to go very wrong, very
quickly. My advice to the OP is to re-evaluate why it is you "need" to do
this in a synchronous manner. Recursively running the run loop in and of
itself will not accomplish what you want anyway- the run loop will run, and
ostensibly the call back will take place. Now what? How do you return the
result from the callback back to the function/method that has recursively
run the run loop? The run loop does't return anything, it just "runs".
Assuming that you solve that problem, synchronously waiting for a result is
just a "one-shot" affair. Once it "happens", it's not going to "happen"
again. Wrapping this mess up in a while() loop that keeps calling
CFRunLoopRun() and 'synchronously' getting the result from the call back is
no different than if you had just registered for the callback and returned
in the first place.
_______________________________________________
Cocoa-dev mailing list (email@hidden)
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:
This email sent to email@hidden