Follow-up questions on sample class ThreadSafeQueue

Christiaan Hofman cmhofman at gmail.com
Wed May 16 01:37:47 PDT 2007


On 16 May 2007, at 2:32 AM, Duncan Champney wrote:

>
> On May 15, 2007, at 7:37 PM, Shawn Erickson wrote:
>
>> On 5/15/07, Duncan Champney <duncanc at aol.com> wrote:
>>> Chris,
>>>
>>> Thanks for the link to the ThreadSafeQueue post. It makes good sense
>>> to me to use NSConditionLock to manage shared access to a job queue.
>>>
>>> I have a couple of follow-up questions.
>>>
>>> I'm a little unclear on how the worker threads would use the
>>> ThreadSafeQueue. I would think the ThreadSafeQueue object's methods
>>> would run on the main thread, and the worker threads would call  
>>> those
>>> methods using performSelectorOnMainThread.
>>
>> Why do you think that? The whole point of the class is to allow
>> multiple threads to utilize the same queue directly. That is why it
>> uses NSConditionLock to protect the data structure it manages.
>
> Shawn,
>
> Thanks for the reply. I'm still trying to wrap my head around the  
> subtleties of multi-threading. I understand you now.
>
>>
>>> Also, I'm puzzled by a couple of lines in the method implementation.
>>> Why do the methods in -dequeue and -tryDequeue retain and  
>>> autorelease
>>> the object from "elements" in the same call. Here's the line from
>>> tryDequeue:
>>>
>>>        element = [[[elements objectAtIndex:0] retain] autorelease];
>>
>> That retains the objects and balances that retain with an  
>> autorelease.
>> That ensures that the object will continue to exist at least until
>> sometime in the future when the current autorelease pool is released
>> (drained).
>>
>> Why is this done? Well the removeObjectAtIndex: message could result
>> in the "element" object being deallocated because the elements array
>> could be the last object holding a retain on "element".
>>
>>> The retain and autorelease calls would seem to cancel each other  
>>> out.
>>
>> That is true but not immediately.
>>
>>> The retain call would increase the retain count for the object in
>>> "elements", and then the autorelease would immediately decrement it,
>>> for a net null effect.
>>
>> No autorelease doesn't immediately decrement the retain count. Review
>> the concept of NSAutoreleasePools.
>
> I just did what you suggested and read the description of  
> NSAutoreleasePool VERY carefully.
>
> The point I didn't understand before was that only an app's main  
> thread automatically releases objects in the autorelease pool (when  
> deallocating the autoreleasePool on the next pass through the event  
> loop.) Secondary threads don't release objects in their autorelease  
> pools automatically - they have to deallocate their autorelease  
> pools explicitly in order for the objects in the pool to be  
> released. Here's the relevant text:
>
>
>    NSAutoreleasePool objects are automatically created and  
> destroyed in the main thread of applications based on the  
> Application Kit, so your code normally does not  have to
>
>    deal with them. The Application Kit creates a pool at the  
> beginning of the event loop and releases it at the end, thereby  
> periodically releasing any autoreleased objects
>
>    generated while processing events.
>
>
> Thus when you execute the example statement I gave before
>
>    element = [[[elements objectAtIndex:0] retain] autorelease];
>
> from a secondary thread, the retain statement increments the retain  
> count, but the autorelease only adds the object to the autorlease  
> pool. Since the autorelease pool for a secondary thread isn't  
> deallocated automatically, the objects listed don't get balancing  
> release calls until the thread terminates or the autorelease pool  
> is deallocated.
>

Yes, that's why you should always create/release an autorelease pool  
on any secondary thread you create. For example by running the  
runloop on the secondary thread like this:

NSAutoReleasePool *pool = nil;
BOOL didRun = YES;
while (shouldKeepRunning && didRun) {
	[pool release];
	pool = [[NSAutoReleasePool alloc] init];
	didRun = [NSAutoreleasePool currentRunLoop]  
runMode:NSDefaultRunnLoopMode beforeDate:[NSDate distantFuture];
}
[pool release];

Christiaan




More information about the MacOSX-dev mailing list