Greg,
So, from what you are saying, either of these snippets should be valid, right?
> +(id)sharedInstance{
> static id _sharedInstance = nil;
>
> if (!_sharedInstance){
> @synchronized([self class]){
> if (!_sharedInstance){
> id sharedInstance = [[super allocWithZone:NULL] init];
> OSMemoryBarrier();
> _sharedInstance = sharedInstance;
> }
> }
> }
>
> OSMemoryBarrier();
> return _sharedInstance;
> }
vs
> +(id)sharedInstance{
> static id _sharedInstance = nil;
>
> static dispatch_once_t onceToken;
> dispatch_once(&onceToken, ^{
> _sharedInstance = [[super allocWithZone:NULL] init];
> });
>
> return _sharedInstance;
> }
Any massive advantages / disadvantages with either approach?
-Richard
On 08/12/2012, at 4:45:37 PM, Greg Parker <[email protected]> wrote:
> On Dec 8, 2012, at 11:17 AM, Steve Sisak <[email protected]> wrote:
>> At 10:24 AM -0800 12/8/12, Kyle Sluder wrote:
>>> On Dec 8, 2012, at 10:06 AM, Steve Sisak <[email protected]> wrote:
>>>
>>>> Further, if writes were not complete at the end of the block, the
>>>> construct would besentially useless for its intended purpose.
>>>
>>> By the way, you're wrong about this too. All @synchronized does is act as a
>>> mutex around a code block. It does not cause the compiler to reorder
>>> instructions and issue memory barriers in such a way that initialization is
>>> guaranteed to precede assignment from the perspective of all threads.
>>
>> Please cite a source for this assertion.
>
> Source: me, the author of the current @synchronized implementation.
> @synchronized performs the same synchronization as a pthread mutex.
>
>
>> From:
>>
>> <https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html>
>>
>> "If you are already using a mutex to protect a section of code, do not
>> automatically assume you need to use the volatile keyword to protect
>> important variables inside that section. A mutex includes a memory barrier
>> to ensure the proper ordering of load and store operations."
>
> To a close approximation, you should pretend that `volatile` does not exist
> in C-based languages.
>
> The above says that if you already have mutexes then you do not need
> `volatile`. The mutex alone does all of the work.
>
> Conversely, `volatile` with no mutex is also not a safe multithreading
> pattern.
>
>
>> I acknowledge that, without proper memory barriers, double-checked locking
>> is problematic, but am providing an example using a construct which I'm
>> fairly sure uses proper memory barriers.
>>
>> - (NSDictionary *)someDictionary;
>> {
>> if (!_someDictionary)
>> {
>> @synchronized (self)
>> {
>> if (!_someDictionary)
>> {
>> // create a temp dictionary (might take some time)
>> _someDictionary = temp;
>> }
>> }
>> }
>>
>> return _someDictionary;
>> }
>
>
> The example provided does not use proper memory barriers.
>
> In general, memory barriers need to occur in pairs, one on each thread. The
> coordination of the two memory barriers achieves the desired synchronization,
> so that both sides observe events occurring in the same order.
>
> Mutexes and similar constructs achieve this. The mutex lock() and unlock()
> procedures form a barrier pair. Code running with the mutex held is therefore
> correctly synchronized with respect to other code that runs with the mutex
> held. But code running outside the mutex is not protected, because it didn't
> call the barrier inside the lock() procedure.
>
> In faulty double-checked locking code, the problem is that the writer has a
> memory barrier but the reader does not. Because it has no barriers, the
> reader may observe events occur out of the desired order. That's why it
> fails. (Here the "writer" is the thread actually calling the initializer and
> the "reader" is a second thread simultaneously performing the double-check
> sequence.)
>
> (Faulty double-checked locking code has a second problem because the
> writer-side barrier inside the mutex unlock is the wrong barrier to use with
> a reader that is not locking the mutex.)
>
> You need to do one of two things to fix the reader side of a double-checked
> lock:
> * add appropriate barriers to the reader side, or
> * cheat in a way that is guaranteed to work on all architectures you care
> about.
>
> dispatch_once() actually cheats. It performs a very expensive barrier on the
> writer side (much more expensive than the barriers used in ordinary mutexes
> and @synchronized), which guarantees that no barrier is needed on the reader
> side on the CPUs that run OS X and iOS. The expensive barrier on the reader
> side is an acceptable trade-off because the writer path runs only once.
>
>
> --
> Greg Parker [email protected] Runtime Wrangler
>
>
>
> _______________________________________________
>
> Cocoa-dev mailing list ([email protected])
>
> 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:
> https://lists.apple.com/mailman/options/cocoa-dev/heardrwt%40gmail.com
>
> This email sent to [email protected]
_______________________________________________
Cocoa-dev mailing list ([email protected])
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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com
This email sent to [email protected]