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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…