9

Coming from Java I'm trying to learn thread safety in Objective-C. So far I've leaned that

  • @synchronized blocks prevent concurrent access to the same block of code
  • volatile variables assure visibility of changes accross threads
  • OSMemoryBarrier(); assures proper ordering of access

My question is: Does one of those imply one or more of the others? If I want all three, do I need to use all three techniques?

Example:

volatile int first = 0;
volatile int second = 0;

[...]

@synchronized {
    OSMemoryBarrier();
    first++;
    OSMemoryBarrier();
    second++;
    OSMemoryBarrier();
}

In Java all three are assured when entering and leaving a synchronized block and when reading or writing a volatile variable. True?

Twilite
  • 873
  • 9
  • 22

2 Answers2

4

The @synchronized directive gets converted as follows...

- (NSString *)myString {
  @synchronized(self) {
    return [[myString retain] autorelease];
  }
}

becomes...

- (NSString *)myString {
  NSString *retval = nil;
  pthread_mutex_t *self_mutex = LOOK_UP_MUTEX(self);
  pthread_mutex_lock(self_mutex);
  retval = [[myString retain] autorelease];
  pthread_mutex_unlock(self_mutex);
  return retval;
}
Simon Lee
  • 22,304
  • 4
  • 41
  • 45
  • So entering and leaving the synchronized block constitutes the passing of memory barriers? And if access to a variable is protected by a synchronized block, the variable doesn't need to be volatile, because changes are always visible to other threads? – Twilite Oct 25 '11 at 15:51
  • I found more on volatile in the answers of this question: http://stackoverflow.com/questions/6866206/volatile-and-createthread It seems, volatile does not pose a memory barrier and is useless for synchronization of access among threads. – Twilite Oct 26 '11 at 07:46
2

@synchronized doesn't protect a block of code from being reentered - it prevents executing any code that also uses @synchronized with the same object. So if you have two methods

- (void)method1 {
    @synchronized (self) { dothis (); }
}
- (void)method2 {
    @synchronized (self) { dothat (); }
}

and two different threads call method1 and method2 for the same object, then dothis() and dothat() will be called one after the other. Of course that's also true if two different threads call method1 for the same object. @synchronized doesn't stop you from entering a block on the same thread though, so in the example above dothis() could call [self method2] and it wouldn't be blocked.

If you are using volatile or OSMemoryBarrier() then I suggest that your design is much, much, much too complicated and you will run into trouble sooner or later.

gnasher729
  • 51,477
  • 5
  • 75
  • 98