Mailing Lists: Apple Mailing Lists
Image of Mac OS face in stamp
Locks, cache coherency, @synchronized, double-checked locking, and lots and lots of doubts
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Locks, cache coherency, @synchronized, double-checked locking, and lots and lots of doubts



I'm a little confused about thread-safety in Objective-C. Take, for example, this article on double-checked locking:

http://wincent.com/a/about/wincent/weblog/archives/2006/08/ doublechecked_l.php

Basically, it says that double-checked locking is not safe unless it is propped up with appropriate memory barriers. There are plenty of other articles out there that reaffirm this exact same point (although I haven't found too many explicitly for Objective-C).

I accept that point, but now I'm looking at the slower (always-lock) alternative for the once-off initialization pattern and I have lingering doubts that it is safe. These doubts were prompted by reading the latest post to the Google Mac Blog:

	http://googlemac.blogspot.com/2006/11/getting-loaded.html

Which says that previous advice about once-off initialization:

	http://googlemac.blogspot.com/2006/11/synchronized-swimming-part-2.html

Is actually a bad thing, for reasons stated here:

	http://avitzur.hax.com/2006/11/efficient_thread_safe_static_i.html

So I accept that that point too, but I am struggling to understand it, and as a result I am doubting that even the slow (always-lock) pattern will work:

+ (void)onceOnlyInit
{
    static BOOL initialized = NO;
    @synchronized (thing)
    {
        if (!initialized)
        {
            PerformInitialization();
            initialized = YES;
        }
    }
}

Now there are two things that are necessary in order for this to be totally thread safe:

1. "initialized" must not be set to YES prior to PerformInitialization () actually being completed (that is, no thread may "see" "initialized" as being YES prior to PerformInitialization() actually being finished).

2. No thread should be allowed to "see" "initialized" as being NO if another thread has actually set it to YES.

So we can minimize the likelihood of the compiler reordering "PerformInitialization()" and "initialized = YES" by declaring it as "volatile". The double-checking locking examples also insert memory barriers to guarantee (1) and (2).

But what happens here if you don't use memory barriers in the always- lock case?

1. Imagine two threads racing to call the "onceOnlyInit" method

2. First thread hits the syncrhonized block and obtains a lock

3. Second thread running on another core hits the synchronized block and is forced to wait

4. First thread checks "initialized", sees it is NO, and so calls PerformInitialization()

4. First thread sets "initialized" to YES

5. First thread leaves synchronized block

6. Second thread is now allowed to enter synchronized block

7. Second thread will see initialized as YES if and only if the copy of the variable visible to its core has been updated to reflect the value set by the other thread running on another core with another cache...

Basically, I'm looking at this pattern and doubting it. Will it also only be safe with memory barriers?

+ (void)onceOnlyInit
{
    static volatile BOOL initialized = NO;
    @synchronized (thing)
    {
        Barrier();
        if (!initialized)
        {
            PerformInitialization();
            Barrier();
            initialized = YES;
        }
    }
}

In fact, I am now looking at just about every piece of code that uses @syncrhonized and starting to feel uneasy about it...

_______________________________________________
Do not post admin requests to the list. They will be ignored.
Objc-language mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden




Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Contact Apple | Terms of Use | Privacy Policy

Copyright © 2011 Apple Inc. All rights reserved.