I guess @synchronized blocks are not object dependent but thread dependent...right? In that case why do we pass self?
@synchronized
is a construct provided by the language to create synchronized scopes. As it would be highly inefficient to use a simple global shared mutex, and thus serializing every single @synchronized
scope in the application, the language allows us to specify a synchronization point.
Then it's up to the developer(s) to decide which synchronization points are appropriate for the task.
On an instance method, using self is common: the instance is the synchronization point. The @synchronized(self)
scope can be called on any number of instances, but only once for a given instance. Every @synchronized(self)
scope will be serialized for a given instance.
Of course, you are free to use another synchronization point if you want to do so. You can use the class (@synchronized(self.class)
) or anything else that suits your needs.
I question this practice, as it is a known anti-pattern in other languages. The crux of the issue is that someone else could also synchronize
on your object, possibly causing deadlocks and other issues that would not have been present had you been using a private NSObject for the lock. For example:
@implementation foo
-(void) bar
{
@synchronized(self) {
@synchronized(sharedLock) {
//do something
}
}
}
Foo* foo = [[Foo alloc] init];
@synchronized(sharedLock) {
@synchronized(foo) {
//do something
}
}
//in another thread
[foo bar];
The object passed in is used to differentiate which @synchronized
blocks correspond to locking each other. Using self
is often convenient, but sometimes it’s a good idea to use some other object if you want to only synchronise smaller, more specific sections of code (eg. synchronise all access to a specific NSMutableDictionary
, rather than synchronising everything in the whole instance)
I’m not sure what you mean by “thread dependent”. The purpose of @synchronized
is for blocks of code that may be running on different threads, and you need to ensure only 1 runs at any time, without overlapping. Important for performing actions that aren’t thread-safe (like mutating collections, for example).
© 2022 - 2024 — McMap. All rights reserved.