What is the parameter that @synchronized() takes
Asked Answered
V

2

9

I know what @synchronized() does, but...
sometimes we have:

1- @synchronized(self)
2- @synchronized([MyClass class])
3- @synchrinized(myObj)

What is the difference, and what is the parameter I should pass to this block ?

Venepuncture answered 18/3, 2014 at 11:58 Comment(5)
You should pass @synchronized(self)Blotter
Similar question: Should I synchronize with self or with the method argument?.Berryberryhill
@Natarajan, why ? always ?Venepuncture
@synchronize() is same NSLock i guess. Used to make it as thread safePhenix
you should be sure not guess :) I am asking what is the parameter that should be passed @AnilVenepuncture
B
14

From the documentation:

The object passed to the @synchronized directive is a unique identifier used to distinguish the protected block. If you execute the preceding method in two different threads, passing a different object for the anObj parameter on each thread, each would take its lock and continue processing without being blocked by the other. If you pass the same object in both cases, however, one of the threads would acquire the lock first and the other would block until the first thread completed the critical section.

So it depends on what you want to protect from being executed simultaneously, and there are applications for all three cases.

For example, in

-(void)addToMyArray1:(id)obj
{
    @synchronized(self) {
        [self.myArray1 addObject:obj];
    }
}

-(void)addToMyArray2:(id)obj
{
    @synchronized(self) {
        [self.myArray2 addObject:obj];
    }
}

both @synchronized blocks cannot be executed simultaneously by two threads calling the method on the same instance (self), thus protecting simultaneous access to the arrays from different threads.

But it also prevents the block from the first method to be executed simultaneously executed with the block from the second method, because they use the same lock self. Therefore, for more fine-grained locking, you could use different locks:

-(void)addToMyArray1:(id)obj
{
    @synchronized(self.myArray1) {
        [self.myArray1 addObject:obj];
    }
}

-(void)addToMyArray2:(id)obj
{
    @synchronized(self.myArray2) {
        [self.myArray2 addObject:obj];
    }
}

Now the simultaneous access to self.myArray1 and self.myArray2 from different threads is still protected, but independently of each other.

A lock on the class can be used to protect access to a global variable. This is just a trivial example for demonstration purposes:

static int numberOfInstances = 0;

-(id)init
{
    self = [super init];
    if (self) {
        @synchronized([self class]) {
            numberOfInstances++;
        }
    }
}
Berryberryhill answered 18/3, 2014 at 12:37 Comment(5)
better to pass the critical section than passing self everytime right ? in this case _objVenepuncture
@Basheer_CAD: I do not understand you question. What is _obj ?Berryberryhill
for example I am using a method to change _obj (writing by multiple threads), it's better to use @synchronized(_obj) and then change this object inside {...}. Just in case self is used as a token in other @synchr.. block from another thread ?Venepuncture
@Basheer_CAD: Yes, if you have a single object to protect (as the arrays in my answer) then you can just lock this object (that's actually simpler and I have updated the answer accordingly). - But there might be more complicated cases (e.g. a sequence of statements to protect) that need a dedicated lock.Berryberryhill
If I understood, is the first example protecting array1 and array2 both?Francoisefrancolin
U
-2

@synchronized should have the same object passed each time. So @synchronized(self) would work best.

Unmixed answered 18/3, 2014 at 12:4 Comment(3)
That depends on what you want to protect. There are also use-cases for @synchronized([MyClass class]) or @ synchronized(someObj).Berryberryhill
@MartinR, yes probably when you have a singleton ?Venepuncture
If you have a singleton, it wouldn't make a difference since there is only one instance. No, it just depends on the situation. If performing the same code for any other object of the same class would be a problem, you synchronize on the class. Also to remember: "@synchronized" should be used for the smallest possible amount of time (so do all calculations outside the "@synchronized") and try avoiding nested "@synchronized" statements on different objects to avoid deadlocks.Belva

© 2022 - 2024 — McMap. All rights reserved.