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: David Duncan <email@hidden>
- Date: Thu, 14 Apr 2011 09:40:50 -0700
On Apr 14, 2011, at 9:19 AM, Jonathan Taylor wrote:
> Hi WT,
>
>>> If I understand you correctly, what you're saying about your variable "__block SomeObjType foo" is not true. Regardless of the __block qualifier, foo is effectively a stack-based variable, so two simultaneously-executing threads have their own independent instance of that variable. There can be no "cross-talk" between the variables in separate threads - all you are doing is enabling the block that a given thread executes to have access to that specific thread's stack variable.
>>
>> I'm afraid you're incorrect there. According to the documentation (or, more precisely, my understanding of the documentation), a variable qualified with __block starts in the stack but is moved to the heap, precisely because it's shared by all blocks capturing it and by all function scopes where it's declared. Therefore, I do not believe "two simultaneously-executing threads have their own independent instance of that variable" to be true.
>
> 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.
>>> 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;
}
--
David Duncan
_______________________________________________
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