Re: Lockless thread-safe accessor using blocks: how to?
Re: Lockless thread-safe accessor using blocks: how to?
- Subject: Re: Lockless thread-safe accessor using blocks: how to?
- From: WT <email@hidden>
- Date: Thu, 14 Apr 2011 14:02:13 -0300
Hi David,
thanks for pitching in.
On Apr 14, 2011, at 1:40 PM, David Duncan wrote:
>> I tested this out before replying as I wasn't 100% certain. It may be that we have misunderstood each other somehow, but the following code (in a clean new project) was what I used to confirm to myself that two concurrently-executing threads have independent instances of the variable:
>> http://www.dur.ac.uk/j.m.taylor/block_test_code.m
>
> On this point Jonathan is correct. What __block does is ensure that a declared variable has the ability to survive its stack frame, not that a variable of that name is shared with all invocations of that stack frame. If you want a variable that will be shared with all instances of that stack frame, you want the "static" qualifier.
I see. It's final, then: I have misunderstood the documentation. Thank you both for pointing me in the right direction.
>>>> However I don't think you should need to do this anyway. I would change your code to something like this:
>>>>
>>>> - (SomeObjType) foo
>>>> {
>>>> dispatch_sync(queue,
>>>> ^{
>>>> // Code in this block ensures bah is valid
>>>> if (nil == bah)
>>>> {
>>>> // Code to compute and store bah goes here
>>>> }
>>>> });
>>>>
>>>> return bah;
>>>> }
>
>
> Fundamentally however, this will not work. If you want to do lazy initialization of a variable with thread safety then you should use dispatch_once() to initialize the variable. This is also not something you can do with a __block or static variable (unless you want all instances to have the same value, which seems to be against the way you've declared the method). Basically you need to do this:
>
> - (SomeObjectType) foo
> {
> dispatch_once(&ivar_predicate, ^ { ivar_value = /* initialization */ });
> return ivar_value;
> }
I looked at dispatch_once() at one point, but I'm still confused by how it works. In any case, here's an actual example of where I use the pattern Jonathan suggested, and I can't see why it would not work.
stSerialQueue is a static variable in the class where -shortStyleDateFormatter is declared.
shortStyleDateFormatter_ is an ivar in that same class, backing the property for which the accessor is being written.
WLT_GCDUtils' +dispatchToQueue: async: guarantees that the dispatch is deadlock-free regardless of which thread the block is executed in.
- (NSDateFormatter*) shortStyleDateFormatter;
{
[WLT_GCDUtils dispatchToQueue: stSerialQueue
async: NO
block:
^{
if (nil == shortStyleDateFormatter_)
{
shortStyleDateFormatter_ = [[NSDateFormatter alloc] init];
[shortStyleDateFormatter_ setLocale:
[NSLocale autoupdatingCurrentLocale]];
[shortStyleDateFormatter_ setDateStyle:
NSDateFormatterShortStyle];
}
}];
return shortStyleDateFormatter_;
}
// In WLT_GCDUtils.m
+ (void) dispatchToQueue: (dispatch_queue_t) queue
async: (BOOL) async
block: (void (^)(void)) block;
{
if (dispatch_get_current_queue() != queue)
{
if (async)
{
dispatch_async(queue, block);
}
else
{
dispatch_sync(queue, block);
}
}
else // already in target queue
{
// Just in case we might need one...
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
block();
[pool release];
}
}
Thanks again for your help.
WT_______________________________________________
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