How does #synchronized lock/unlock in Objective-C? - objective-c

Does #synchronized not use "lock" and "unlock" to achieve mutual exclusion? How does it do lock/unlock then?
The output of the following program is only "Hello World".
#interface MyLock: NSLock<NSLocking>
#end
#implementation MyLock
- (id)init {
return [super init];
}
- (void)lock {
NSLog(#"before lock");
[super lock];
NSLog(#"after lock");
}
- (void)unlock {
NSLog(#"before unlock");
[super unlock];
NSLog(#"after unlock");
}
#end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
MyLock *lock = [[MyLock new] autorelease];
#synchronized(lock) {
NSLog(#"Hello World");
}
[pool drain];
}

The Objective-C language level synchronization uses the mutex, just like NSLock does. Semantically there are some small technical differences, but it is basically correct to think of them as two separate interfaces implemented on top of a common (more primitive) entity.
In particular with a NSLock you have an explicit lock whereas with #synchronized you have an implicit lock associated with the object you are using to synchronize. The benefit of the language level locking is the compiler understands it so it can deal with scoping issues, but mechanically they behave basically the same.
You can think of #synchronized as a compiler rewrite:
- (NSString *)myString {
#synchronized(self) {
return [[myString retain] autorelease];
}
}
is transformed into:
- (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;
}
That is not exactly correct because the actual transform is more complex and uses recursive locks, but it should get the point across.

In Objective-C, a #synchronized block handles locking and unlocking (as well as possible exceptions) automatically for you. The runtime dynamically essentially generates an NSRecursiveLock that is associated with the object you're synchronizing on. This Apple documentation explains it in more detail. This is why you're not seeing the log messages from your NSLock subclass — the object you synchronize on can be anything, not just an NSLock.
Basically, #synchronized (...) is a convenience construct that streamlines your code. Like most simplifying abstractions, it has associated overhead (think of it as a hidden cost), and it's good to be aware of that, but raw performance is probably not the supreme goal when using such constructs anyway.

Actually
{
#synchronized(self) {
return [[myString retain] autorelease];
}
}
transforms directly into:
// needs #import <objc/objc-sync.h>
{
objc_sync_enter(self)
id retVal = [[myString retain] autorelease];
objc_sync_exit(self);
return retVal;
}
This API available since iOS 2.0 and imported using...
#import <objc/objc-sync.h>

Apple's implementation of #synchronized is open source and it can be found here. Mike ash wrote two really interesting post about this subject:
Locks, Thread Safety, and Swift
Let's Build #synchronized
In a nutshell it has a table that maps object pointers (using their memory addresses as keys) to pthread_mutex_t locks, which are locked and unlocked as needed.

It just associates a semaphore with every object, and uses that.

Related

Thread sanitizer issue in Xcode with atomic/synchronized properties & NSLock

I have a property declared on an object in Objective-C that's called from multiple threads:
#property (atomic, strong) NSNumber *validLock;
In my setter, I do the following:
#synchronized(self.validLock) {
self.validLock = #YES;
}
In my getter, I do the following:
#synchronized(self.validLock) {
if (self.validLock.boolValue) {
...
}
}
Despite all these precautions, the thread sanitizer in Xcode still breaks on the #synchronized getter line with a comment "Data Race detected."
I even ditched the '#synchronized' idea and went all-in with NSLock to no avail.
This is becoming laughable, as this also gets tagged on [myLock lock] by the Xcode thread sanitizer:
NSLock *myLock = [[NSLock alloc] init];
...
[myLock lock];
self.validLock = #NO;
[myLock unlock];
What am I doing wrong?
This isn't particularly meaningful:
#synchronized(self.validLock) {
self.validLock = #YES;
}
I think you're expecting this to synchronize on "the validLock property of self" but that's not what the parameter means. You're synchronizing on the NSNumber that is currently pointed to by validLock (an NSNumber that you then replace). Since this is not the same object that you synchronize against elsewhere, this doesn't do much.
Similarly, if this code is all in the same context (which is what your example suggests), it doesn't do anything either:
NSLock *myLock = [[NSLock alloc] init];
...
[myLock lock];
self.validLock = #NO;
[myLock unlock];
Each thread would have its own lock.
First, you really want to avoid both NSLock and #synchronized. They've been superseded by GCD for many years now. See the Concurrency Programming Guide for full details.
If you really want to use #synchronized (realizing that it is pretty inflexible and quite slow), then typically you call it on self.
#synchronized(self) {
self.validLock = #YES;
}
But in any case, it has to be on the same actual object (not just the same name of an object).
If you're going to use NSLock, you need to make sure everyone is sharing the same actual lock, so for a single instance it needs to be a property. For multiple instances it needs to be a global or at least a class property.

Global NSOperationQueue

I'm trying to create a NSOperationQueue and add a NSOperation to it. Later I wan't to check if the queue is running and maybe abort it. All of that is supposed to be called from within different functions. What's the best approach to do this? I would be glad for a code example. Thanks!
I would create an operation queue that's managed by a singleton.
First, create your singleton class. It will provide access to the NSOperationQueue. Let's call the singleton MyGlobalQueueManager.
It will have an ivar called myGlobalQueue:
#property (nonatomic) NSOperationQueue* myGlobalQueue;
In the .m file of MyGlobalQueueManager, create a fairly standard init method that will set up the operation queue:
- (id)init
{
self = [super init];
if (self)
{
myGlobalOperationQueue = [[NSOperationQueue alloc] init];
}
return self;
}
Now, the method that provides itself as a singleton. Again, this is pretty standard stuff:
+ (MyGlobalQueueManager *)sharedInstance
{
static MyGlobalQueueManager *sharedInstance = nil;
static dispatch_once_t isDispatched;
dispatch_once(&isDispatched, ^
{
sharedInstance = [[MyGlobalQueueManager alloc] init];
});
return sharedInstance;
}
Let's access that queue from wherever you want to use it:
MyGlobalQueueManager* myGlobalQueueManager = [MyGlobalQueueManager sharedInstance];
NSOperationQueue *myGlobalQueue = myGlobalQueueManager.myGlobalOperationQueue;
You can then add operations to that queue as you fancy.
How to know if anythings queued?
NSUInteger count = [myGlobalQueue operationCount];
How to abort? Cancel everything as follows:
[myGlobalQueue cancelAllOperations];
Cancelling of course depends on the operations. If you're writing custom NSOperation classes, you'll need to handle that yourself.
I find NSOperation and NSOperationQueue to be fairly easy to use and quite straightforward.
A great document to read for all this is the Concurrency Programming Guide. Specifically, have a look at Operation Queues
An easier way to do it is to make a "globally visible" function. AKA, declare it in a public header:
extern NSOperationQueue * SharedQueue();
and define it within your compilation "unit" - but outside any #implementation.
NSOperationQueue *SharedOperationQueue()
{
static NSOperationQueue * _SharedQueue = nil;
return _SharedQueue ?: ^{ _SharedQueue = NSOperationQueue.new;
_SharedQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount;
return _SharedQueue;
}();
}
As a little bonus.. #define it with an "alias".. and you can REALLy abuse it!
#define MY_SOQ SharedOperationQueue()
[MY_SOQ addOperationWithBlock:^{ /* GO CRAZY */ }];

Using #synchronized, volatile and OSMemoryBarrier() all together. Does one imply the other?

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?
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;
}
#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.

NSMutableDictionary Singleton issue

I am coding Objective-C using the Cocos2D framework, and I have a singleton used for multiple purposes. One new purposes is to get and set character's "states" which are strings. I've recently made an NSDictionary for this purpose, but I have issues with the program freezing up when a method inside the singleton is called.
Here's the singleton code. I'm just leaving in the character state stuff:
.h
#interface ExGlobal : NSObject {
NSArray *charStates_keys;
NSArray *charStates_objects;
NSMutableDictionary *charStates;
}
#property(nonatomic, retain) NSMutableDictionary *charStates;
+(ExGlobal*)sharedSingleton;
- (NSString *)charState:(NSString *)charName;
- (void)set_charState:(NSString *)value forCharName:(NSString *)charName;
#end
.m
#import "ExGlobal.h"
#implementation ExGlobal
#synthesize charStates;
static ExGlobal* _sharedSingleton = nil;
+(ExGlobal*)sharedSingleton {
#synchronized([ExGlobal class]) {
if (!_sharedSingleton) {
[[self alloc] init];
}
return _sharedSingleton;
}
return nil;
}
+(id)alloc {
#synchronized([ExGlobal class]) {
NSAssert(_sharedSingleton == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedSingleton = [super alloc];
return _sharedSingleton;
}
return nil;
}
-(id)init {
self = [super init];
if (self != nil) {
// initialize stuff here
exitName = #"ruinsSkyMid";
sceneChangeKind = #"reborn";
charStates = [[NSMutableDictionary alloc] init];
charStates_keys = [NSArray arrayWithObjects:#"Feathers", #"Hummus", nil];
charStates_objects = [NSArray arrayWithObjects:#"at wall", #"with Feathers", nil];
charStates = [NSMutableDictionary dictionaryWithObjects:charStates_objects forKeys:charStates_keys];
}
return self;
}
- (NSString *)charState:(NSString *)charName{
NSString *value = [charStates objectForKey:charName];
return value;
}
- (void)set_charState:(NSString *)charState forCharName:(NSString *)charName{
[charStates setObject:charState forKey:charName];
}
- (void)dealloc {
//I know it doesn't get called, but just in case
[charStates release];
[super dealloc];
}
#end
It's unclear to me what exactly the issue is when it freezes. When this happens, all I get in the console is:
Program received signal: “EXC_BAD_ACCESS”.
warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.5 (8L1)/Symbols/Developer/usr/lib/libXcodeDebuggerSupport.dylib (file not found).
Previous frame inner to this frame (gdb could not unwind past this frame)
Previous frame inner to this frame (gdb could not unwind past this frame)
Which I'm sure doesn't help finding the issue. I found if I redefine charStates_keys, charStates_objects and charStates inside both the charState and set_charState methods, it seems to work without freezing, except set_charState does not change the state.
It isn't freezing, it is crashing. Hence the EXC_BAD_ACCESS. It looks like your Xcode installation is borked, too, as the two messages following should not happen.
Note that methods should not have _s in the name; not a cause of the problem, but a comment on following convention.
You aren't retaining charStates and that is likely the cause of the crash.
Not an answer as such but I didn't have enough space in the comments field above to post this, but it might be useful.
As bbum already said, your lack of retaining charStates is likely the problem.
If you are confused about when to retain and not retain objects there's a really good book called "Learn Objective-C on the Mac" and I know it's a Mac book but most of it applies to iPhone too. On page 171 of chapter 9 (Memory Management) it talks about the "Memory Management Rules" and how if you are confused about when to retain or not then you don't understand the simple rules of Objective C memory management.
Essentially if you create an object using new, alloc or copy, then the retain count is automatically set to 1 so the object is retained and does not require you to retain it and will require a subsequent release to deallocate.
If you create the object any other way then the object will be an autoreleased object.
Obviously these rules only apply within the standard iOS libraries and can't necessarily be applied to third party libraries.
I recommend anyone who doesn't fully understand memory management in Objective C read this book. I found highly enlightening even for my iPhone work.
Hope that helps/.

I must enclose object creation/release with try/finally?

In Delphi, is normal do this:
ob = TObject.create;
try
//code
finally
ob.free;
end;
I wonder if that is similar in Obj-c.
You could do it that way, but exceptions tend to have a high cost in Objective-C. There are some differences in their performance between the 32-bit and 64-bit ABIs, as well as the interaction between Objective-C exceptions and C++ exceptions.
An alternative is to create your objects such that they are autoreleased and only retain them before your method ends.
SomeClass *object = [[[SomeClass alloc] init] autorelease];
/* deadly code here */
return [object retain];
This way even if your code experiences an exception your object will be released the next time the autorelease pool is drained (usually at the end of the event loop), assuming that the exception is not fatal and causes your program to crash.
Apple has some documentation about Obj-C exceptions
and the release notes for Leopard towards the end discuss the changes in the 64-bit ABI.
No. Objective-C does support exceptions and you see them in Cocoa infrequently (NSError is the direction Apple is headed) but you definitely wouldn't use them every time you initialize or release an object.
I'm certainly no expert in Obj-C but the fact that it provides (what people have asked in Delphi) the compound try/catch/finally, gives you the choice to use that to program defensively like in Delphi:
#try {
// protected block
}
#catch (id theException) {
// do smthing with theException
}
#finally {
// clean up code
}
And I would argue that if programmers used the #finally more often, there would be less bugs in their developments.
good answers, however...
I stand to be corrected, but it is my understanding that #try {} #finally {} is different in concept and therefore application to #try {} #catch {} #finally {}, in that if you don't raise any exceptions there is minimal overhead, however when exceptions are raised (which should be by definition, the "exception rather than the rule"), they serve to protect the resource being wrapped, leaving a #catch handler further up the food chain to deal with logic side of dealing with the exception.
as an example, here is a construct i often use when i have to return an autoreleased value that would autorealease a lot of extraneous data into the callers pool, if it were not for the #try/#finally/drain/autorelease construct you see here.
+(NSArray *) arrayOfUrlPrefixAssociatedUrlArraysFromUnsortedArrayOfUrlStrings:(NSArray *)urlStrings {
NSArray *arrayResult = nil;
NSAutoreleasePool *wader = [[NSAutoreleasePool alloc] init];
#try {
NSMutableDictionary *result = [NSMutableDictionary dictionary];
for (NSString *urlString in urlStrings) {
BOOL addedToPrior = NO;
for (NSString *prefix in result.allKeys) {
if ([urlString hasPrefix:prefix]) {
[(NSMutableArray *) [result objectForKey:prefix] addObject:urlString];
addedToPrior = YES;
break;
}
}
if (!addedToPrior) {
[result setObject:[NSMutableArray arrayWithObject:urlString] forKey:[self urlPrefixFromUrlString:urlString]];
}
}
arrayResult = [[NSArray alloc] initWithArray:[result allValues]];
}
#finally {
[wader drain];
}
return (arrayResult?[arrayResult autorelease]:nil);
}