Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
213 views
in Technique[技术] by (71.8m points)

ios - @synchronized the writing queue makes thread safe?

NSObject *token = [[NSObject alloc] init];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    while (1) {
        @synchronized (token) {
            array = [NSArray arrayWithObject:@"1"];
        }
    }
});

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    while (1) {
        NSLog(@"%@",array);
    }
});

This code won't crash, even there is no @synchronized in the read queue.

As compared,

NSLock *lock = [[NSLock alloc] init];

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    while (1) {
        [lock lock];
        array = [NSArray arrayWithObject:@"1"];
        [lock unlock];
    }
});

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    while (1) {
        NSLog(@"%@",array);
    }
});

This code will crash as array is not thread safe. How does this one-side @synchronized keeps the thread safe?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

How does this one-side @synchronized keeps the thread safe?

It doesn’t.

Using @synchronized (or any synchronization method) for writes, but not for reads, is not thread-safe. Just because your code does not readily crash does not mean it is thread-safe. Both reads and writes must be synchronized. Neither of these two examples, with unsynchronized reads, is thread-safe.

If you want to test for thread-safety, consider the thread sanitizer (TSAN). For example, when I ran the @synchronized example through TSAN, it reported:

WARNING: ThreadSanitizer: data race (pid=89608)
  Read of size 8 at 0x7b0c0007bce8 by thread T1:
    #0 __29-[ViewController viewDidLoad]_block_invoke.14 <null> (MyApp12:x86_64+0x100002e3d)
    #1 __tsan::invoke_and_release_block(void*) <null> (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x74d7b)
    #2 _dispatch_client_callout <null> (libdispatch.dylib:x86_64+0x40af)

  Previous write of size 8 at 0x7b0c0007bce8 by thread T3 (mutexes: write M1679):
    #0 __29-[ViewController viewDidLoad]_block_invoke <null> (MyApp12:x86_64+0x100002c02)
    #1 __tsan::invoke_and_release_block(void*) <null> (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x74d7b)
    #2 _dispatch_client_callout <null> (libdispatch.dylib:x86_64+0x40af)

  Location is heap block of size 48 at 0x7b0c0007bcc0 allocated by main thread:
    #0 malloc <null> (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x5239a)
    #1 _Block_object_assign <null> (libsystem_blocks.dylib:x86_64+0x14fc)
    #2 _Block_copy <null> (libsystem_blocks.dylib:x86_64+0x141c)
    #3 -[ViewController viewDidLoad] <null> (MyApp12:x86_64+0x100002878)
    #4 -[NSViewController _sendViewDidLoad] <null> (AppKit:x86_64+0xb41ce)
    #5 start <null> (libdyld.dylib:x86_64+0x15620)

  Mutex M1679 (0x7b0400004020) created at:
    #0 objc_sync_enter <null> (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x72a45)
    #1 __29-[ViewController viewDidLoad]_block_invoke <null> (MyApp12:x86_64+0x100002b51)
    #2 __tsan::invoke_and_release_block(void*) <null> (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x74d7b)
    #3 _dispatch_client_callout <null> (libdispatch.dylib:x86_64+0x40af)

  Thread T1 (tid=3657833, running) is a GCD worker thread

  Thread T3 (tid=3657837, running) is a GCD worker thread

SUMMARY: ThreadSanitizer: data race (/Users/.../Library/Developer/Xcode/DerivedData/MyApp-ewpoprpgpjgbmrcrkyycvogiazhl/Build/Products/Debug/MyApp12.app/Contents/MacOS/MyApp:x86_64+0x100002e3d) in __29-[ViewController viewDidLoad]_block_invoke.14+0x6d

Whichever synchronization mechanism you use (whether @synchronized, locks, or GCD), both reads and writes must be synchronized. Data race problems are notoriously difficult to manifest, and, as such, one should hesitate to draw any conclusions from an absence of a crash.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...