Can a static variable used as #synchronized parameter? - objective-c

We want to guarantee thread safety for a static variable.
We used another static variable as object in the #synchronized directive. Like this:
static NSString *_saveInProgressLock = #"SaveInProgressLock";
static BOOL _saveInProgress;
+ (BOOL)saveInProgress {
#synchronized(_saveInProgressLock) {
return _saveInProgress;
}
}
+ (void)setSaveInProgress:(BOOL)save {
#synchronized(_saveInProgressLock) {
_saveInProgress = save;
}
}
We are experiencing issues in the app currently on the store, which may be reproduced by preventing the _saveInProgress variable to be set to NO.
Do you see any problem with the above code?
How does it differ from this?
static BOOL _saveInProgress;
+ (BOOL)saveInProgress {
#synchronized([MyClass class]) {
return _saveInProgress;
}
}
+ (void)setSaveInProgress:(BOOL)save {
#synchronized([MyClass class]) {
_saveInProgress = save;
}
}

tl;dr: This is perfectly safe as long as the string literal is unique. If it is not unique there may be (benign) problems, but usually only in Release mode. There may be an easier way to implement this, though.
#synchronized blocks are implemented using the runtime functions objc_sync_enter and objc_sync_exit (source). These functions are implemented using a global (but objc-internal) side table of locks that is keyed by pointer values. On the C-API-level, you could also lock on (void *)42, or in fact any pointer value. It doesn't even matter wether the object is alive, because the pointer is never dereferenced. However, the objc compiler refuses to compile a #synchronized(obj) expression if the obj does not statically typecheck to an id type (of which NSString * is a subtype, so it's okay) and maybe it retains the object (I'm not sure about that), so you should only use it with objects.
There are two critical points to consider though:
if the obj on which you synchronize is the NULL-pointer (nil in Objective C), then objc_sync_enter and objc_sync_exit are no-ops, and this leads to the undesirable situation where the block is performed with absolutely no locking.
If you use the same string value for different #synchronized blocks, the compiler may be smart enough to map them to the same pointer address. Maybe the compiler does not do this now, but it is a perfectly valid optimization that Apple may introduce in the future. So you should make sure that you use unique names. If this happens, two different #synchronized blocks may accidentally use the same lock where the programmer wanted to use different locks. By the way, you can also use [NSObject new] as a lock object.
Synchronizing on a class object ([MyClass class]) is perfectly safe and okay too.
Now for the easier way. If you just have a single BOOL variable that you want to be atomic, you may use lock-free programming:
static BOOL _saveInProgress;
+ (BOOL)saveInProgress {
__sync_synchronize();
return _saveInProgress;
}
+ (void)setSaveInProgress:(BOOL)save {
_saveInProgress = save;
__sync_synchronize();
}
This has much better performance and is just as threadsafe. __sync_synchronize() is a memory barrier.
Note however, that the safety of both solutions depend on how you use them. If you have a save-method somewhere that looks like this:
+ (void)save { // line 21
if(![self saveInProgress]) { // line 22
[self setSaveInProgress:YES]; // line 23
// ... do stuff ...
[self setSaveInProgress:NO]; // line 40
}
}
that +save method is not threadsafe at all, because there is a race condition between line 22 and line 23. (Don't wanna go into details here.. just ask a new question if you need more information.)

Related

Objective-C define block after passing it to a method

Is it possible to define a block after passing it to a method? I want to do this so the code is in somewhat the order it runs in:
// Declare the block
void (^doStuffBlock)(void);
// Pass the block.
[self prepareToDoStuffWithCompletion:doStuffBlock];
// Define the block.
doStuffBlock = ^void() {
// Do stuff
};
doesn't work because inside prepareToDoStuffWithCompletion: the block doStuffBlock is nil.
you should first define the block then pass it to the method:
// Declare the block
void (^doStuffBlock)(void);
// Define the block.
doStuffBlock= ^void() {
// Do stuff
};
// Pass the block.
[self prepareToDoStuffWithCompletion:doStuffBlock];
You could use a typedef.
typedef void (^TypeName)(void);
- (void)bar:(TypeName)completion {
completion();
}
TypeName foo = ^() { /*...*/ };
[self bar:foo];
(My obj-c syntax might be a little rusty, but what you want to do is possible in both Objective-C and Swift.
https://stackoverflow.com/a/29580490/620197
http://goshdarnblocksyntax.com/
If you are certain that the method will run your doStuffBlock after you "define" it, what you could do is have your doStuffBlock capture a variable holding a second block with the real logic of what it should do. You can set the real-logic block after you create doStuffBlock, and you need to make sure that the variable holding the real-logic block is a __block variable, so that changes to the variable in the function scope are seen in the block scope.
__block void (^realLogicBlock)(void);
[self prepareToDoStuffWithCompletion:^{
if (realLogicBlock)
realLogicBlock();
}];
realLogicBlock = ^void() {
// Do stuff
};
You might have to be careful about retain cycles though -- if inside realLogicBlock, you capture a reference to self or to something that will reference the prepareToDoStuffWithCompletion: completion handler, you would have a retain cycle, in which case you may have to introduce a weak reference somewhere.
If you supply the completion handler closure, you are effectively saying “here is the closure I want you to use”.
If you are going to supply the closure later you would probably define a property:
#property (nonatomic, copy, nullable) void (^doStuff)(void);
Then, do not supply the closure when you call the method, but rather refer to this property:
- (void)prepareToDoStuff {
[self somethingAsynchronousWithCompletion:^{
if (self.doStuff) {
self.doStuff();
// if completion handler, you’d often release it when done, e.g.
//
// self.doStuff = nil;
}
}];
}
And, then you can call this method and supply the closure later:
[self prepareToDoStuff];
self.doStuff = ^{
NSLog(#"do stuff done");
};
A few additional considerations:
Make sure you synchronize your access to this doStuff property. E.g., in the above, I am assuming that the somethingAsynchronousWithCompletion is calling its completion handler on the main thread. If not, synchronize your access (like you would any non-thread-safe property in a multithreaded environment).
There is a logical race if you first call the method that will eventually call the block, and only later set that block property. Sometimes that is perfectly fine (e.g. maybe you are just trying to specify what UI to update when the asynchronous process finishes). Other times, the race can bite you. It depends upon the functional intent of the block property.
I would give the block property a name that better reflects its functional purpose (e.g. completionHandler or notificationHandler or didReceiveValue or whatever).

Running a nil block in Objective C [duplicate]

I started using blocks a lot and soon noticed that nil blocks cause bus errors:
typedef void (^SimpleBlock)(void);
SimpleBlock aBlock = nil;
aBlock(); // bus error
This seems to go against the usual behaviour of Objective-C that ignores messages to nil objects:
NSArray *foo = nil;
NSLog(#"%i", [foo count]); // runs fine
Therefore I have to resort to the usual nil check before I use a block:
if (aBlock != nil)
aBlock();
Or use dummy blocks:
aBlock = ^{};
aBlock(); // runs fine
Is there another option? Is there a reason why nil blocks couldn’t be simply a nop?
I'd like to explain this a bit more, with a more complete answer. First let's consider this code:
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
void (^block)() = nil;
block();
}
If you run this then you'll see a crash on the block() line that looks something like this (when run on a 32-bit architecture - that's important):
EXC_BAD_ACCESS (code=2, address=0xc)
So, why is that? Well, the 0xc is the most important bit. The crash means that the processor has tried to read the information at memory address 0xc. This is almost definitely an entirely incorrect thing to do. It's unlikely there's anything there. But why did it try to read this memory location? Well, it's due to the way in which a block is actually constructed under the hood.
When a block is defined, the compiler actually creates a structure on the stack, of this form:
struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
/* Imported variables. */
};
The block is then a pointer to this structure. The fourth member, invoke, of this structure is the interesting one. It is a function pointer, pointing to the code where the block's implementation is held. So the processor tries to jump to that code when a block is invoked. Notice that if you count the number of bytes in the structure before the invoke member, you'll find that there are 12 in decimal, or C in hexadecimal.
So when a block is invoked, the processor takes the address of the block, adds 12 and tries to load the value held at that memory address. It then tries to jump to that address. But if the block is nil then it'll try to read the address 0xc. This is a duff address, clearly, and so we get the segmentation fault.
Now the reason it must be a crash like this rather than silently failing like an Objective-C message call does is really a design choice. Since the compiler is doing the work of deciding how to invoke the block, it would have to inject nil checking code everywhere a block is invoked. This would increase code size and lead to bad performance. Another option would be to use a trampoline which does the nil checking. However this would also incur performance penalty. Objective-C messages already go through a trampoline since they need to look up the method that will actually be invoked. The runtime allows for lazy injection of methods and changing of method implementations, so it's already going through a trampoline anyway. The extra penalty of doing the nil checking is not significant in this case.
For more information, see my blog posts.
Matt Galloway's answer is perfect! Great read!
I just want to add that there are some ways to make life easier. You could define a macro like this:
#define BLOCK_SAFE_RUN(block, ...) block ? block(__VA_ARGS__) : nil
It can take 0 – n arguments. Example of usage
typedef void (^SimpleBlock)(void);
SimpleBlock simpleNilBlock = nil;
SimpleBlock simpleLogBlock = ^{ NSLog(#"working"); };
BLOCK_SAFE_RUN(simpleNilBlock);
BLOCK_SAFE_RUN(simpleLogBlock);
typedef void (^BlockWithArguments)(BOOL arg1, NSString *arg2);
BlockWithArguments argumentsNilBlock = nil;
BlockWithArguments argumentsLogBlock = ^(BOOL arg1, NSString *arg2) { NSLog(#"%#", arg2); };
BLOCK_SAFE_RUN(argumentsNilBlock, YES, #"ok");
BLOCK_SAFE_RUN(argumentsLogBlock, YES, #"ok");
If you want to get the return value of the block and you are not sure if the block exists or not then you are probably better off just typing:
block ? block() : nil;
This way you can easily define the fallback value. In my example 'nil'.
Caveat: I'm no expert in Blocks.
Blocks are objective-c objects but calling a block is not a message, although you could still try [block retain]ing a nil block or other messages.
Hopefully, that (and the links) helps.
This is my simple nicest solution… Maybe there is possible to write one universal run function with those c var-args but I don’t know how to write that.
void run(void (^block)()) {
if (block)block();
}
void runWith(void (^block)(id), id value) {
if (block)block(value);
}

Thread-Safe lazy initialization in getter

I would like to know if both of the following solutions for lazy initialization are correct.
I have a class AppContext that is supposed to hold references to other class that should only exist once (Avoiding making every single one of these classes a singleton). Let's say one of these other classes is called ReferencedClass. That being said, I would like to lazy-initialize the references with defaults, in a thread-safe way.
It has been discussed before, and I have read a lot about it, but I am still unsure. Personal preferences aside, what I would like know is: Are these two solutions a correct way to implemented my desired behavior?
Solution 1: Originally I wanted to implement it like this:
// Getter with lazy initialized default value
- (ReferencedClass *)referencedClass {
// Check if nil. If yes, wait for lock and check again after locking.
if (_referencedClass == nil) {
#synchronized(self) {
if (_referencedClass == nil) {
// Prevent _referencedClass pointing to partially initialized objects
ReferencedClass *temp = [[ReferencedClass alloc] init];
_referencedClass = temp;
}
}
}
return _referencedClass;
}
// Setter
- (void)setReferencedClass:(ReferencedClass *)referencedClass {
#synchronized(self) {
_referencedClass = referencedClass;
}
}
Solution 2: Then I decided to go with GCD instead, so I wrote this:
// Getter with lazy initialized default value
- (ReferencedClass *)referencedClass {
// Check if nil. If yes, wait for "lock" and check again after "locking".
if (_referencedClass == nil) {
dispatch_sync(syncDispatchQueue, ^{
if (_referencedClass == nil) {
// Prevent _referencedClass pointing to partially initialized objects
ReferencedClass *temp = [[ReferencedClass alloc] init];
_referencedClass = temp;
}
});
}
return _referencedClass;
}
// Setter
- (void)setReferencedClass:(ReferencedClass *)referencedClass {
dispatch_sync(syncDispatchQueue, ^{
_referencedClass = referencedClass;
});
}
Of course, somewhere (for example in the init-Method) I have initialized the syncDispatchQueue with something like:
syncDispatchQueue = dispatch_queue_create("com.stackoverflow.lazy", NULL);
Is this correct, thread-safe and deadlock-free code? Can I use the double-checked-locking together with the temp-variable? If this double-checked-locking is not safe, would my code in both cases be safe if I removed the outer checks? I guess so, right?
Thanks very much in advance!
[Side note: I am aware of dispatch_once and that some people say that (in contrary to the Apple documentation) it can also be used with instance variables. For now I would like to use one of these two options though. If possible. ]
As far as I understand it, your "double-checked locking" mechanism is not thread-safe,
because the assigment _referencedClass = ... is not atomic. So one thread might read a partially initialized variable in the outer if (_referencedClass == nil) check.
If you remove the outer checks, both versions look OK to me.
You may be interested in
What advantage(s) does dispatch_sync have over #synchronized?
which has a great answer explaining the differences in implementation and performance.

Obj-C introspection: how to avoid casting all the time?

Hello all,
I've been working on some enumeration routines in Objective-C that perform object introspection. In particular, I'm fast enumerating an NSSet and making sure that the objects therein belong to class BBBallView (an fairly unfortunate name, I agree) before tweaking their properties and/or calling their methods.
In order to make the parser and compiler happy, however, I end up casting the object to its class on every single line; moreover, in order to access its properties, the object's cast has to be in parentheses, otherwise dot notation won't work. This leads to somewhat messy code:
for (id otherBall in self.gameField.subviews) {
if ([otherBall isKindOfClass:[BBBallView class]]) {
if ( !((BBBallView *)otherBall).isEnlarged ) {
CGRect otherFrame = ((BBBallView *)otherBall).frame;
/* ... */
}
}
}
Is there any way to tell the compiler something like "at this point I know that otherBall is a BBBallView, so stop telling me it doesn't respond to these selectors and properties"? That way, one could just write:
for (id otherBall in self.gameField.subviews) {
if ([otherBall isKindOfClass:[BBBallView class]]) {
if ( !otherBall.isEnlarged ) {
CGRect otherFrame = otherBall.frame;
/* ... */
}
}
}
and so on.
I tried otherBall = (BBBallView *)otherBall but "fast enumeration variables can't be modified in ARC by default". Changing the enumeration variable to __strong id fixes it, but doesn't help the fact that any subsequent line gives out errors such as "property isEnlarged not found on object of type 'const __strong id'", so I'm back to square one.
I'm not even sure why exactly this happens: shouldn't the compiler stay out of the way when an variable is of type id? In any case, the whole ordeal particularly messy in methods that need to perform several calculations on objects' properties, as it quickly becomes unreadable with all those parentheses.
Is there any way around this?
Thanks in advance!
You can either create a local temp with the correct type or just not use dot notation.
local temp
for (UIView *view in self.gameField.subviews) {
if ([view isKindOfClass:[BBBallView class]]) {
BBBallView *ballView = view;
if (!ballView.isEnlarged) {
CGRect otherFrame = ballView.frame;
/* ... */
}
}
}
don't use dot notation
for (id otherBall in self.gameField.subviews) {
if ([otherBall isKindOfClass:[BBBallView class]]) {
if ( ![otherBall isEnlarged]) {
CGRect otherFrame = [otherBall frame];
/* ... */
}
}
}
If I was only doing a couple of things I would be tempted to not use dot notation. If it became awkward to read and there was a lot of accesses then I would consider local temp
I think you're struggling because the logic appears misplaced. The language is fighting you because of your program's structure, not because the language is deficient.
Is the parent type of subviews really appropriate? Or are you violating the Liskov Substitution Principle by stuffing a round object in a square type?
You can also ask if is it really appropriate to examine the internals of BBBallView logic from outside? Can you move the logic into the appropriate class?

Using objc_msgSendSuper to invoke a class method

I was going through and replacing #synthesized(self) locks w/ this method
void _ThreadsafeInit(Class theClassToInit, void *volatile *theVariableItLivesIn, void(^InitBlock)(void))
{
//this is what super does :X
struct objc_super mySuper = {
.receiver = (id)theClassToInit,
.super_class = class_getSuperclass(theClassToInit)
};
id (*objc_superAllocTyped)(struct objc_super *, SEL, NSZone *) = (void *)&objc_msgSendSuper;
// id (*objc_superAllocTyped)(id objc_super, SEL, NSZone *) = (void *)&objc_msgSend;
do {
id temp = [(*objc_superAllocTyped)(&mySuper /*theClassToInit*/, #selector(allocWithZone:), NULL) init];//get superclass in case alloc is blocked in this class;
if(OSAtomicCompareAndSwapPtrBarrier(0x0, temp, theVariableItLivesIn)) { //atomic operation forces synchronization
if( InitBlock != NULL ) {
InitBlock(); //only the thread that succesfully set sharedInstance pointer gets here
}
break;
}
else
{
[temp release]; //any thread that fails to set sharedInstance needs to clean up after itself
}
} while (*theVariableItLivesIn == NULL);
}
which while a bit more verbose exhibits significantly better performance in non-contested cases
along with this little macro (excuse poor formatting, it's very simple). To allow the block to be declared after the initial nil check, looks to help LLVM keep the "already initialized" path extremely fast. That's the only one I care about.
#define ThreadsafeFastInit(theClassToInit, theVariableToStoreItIn, aVoidBlockToRunAfterInit) if( theVariableToStoreItIn == nil) { _ThreadsafeInitWithBlock(theClassToInit, (void *)&theVariableToStoreItIn, aVoidBlockToRunAfterInit); }
So initially implemented it using the commented out sections for objc_superAllocTyped (actually first using [theClassToInit allocWithZone:NULL], which was definitely the best approach :) ), which worked great until I realized that most of the singletons in the project had overridden allocWithZone to return the singleton method... infinite loop. So I figured using objc_msgSendSuper should sort it out quickly, but I get this error.
[51431:17c03] +[DataUtils allocWithZone:]: unrecognized selector sent to class 0x4f9584
The error doesn't seem to be related to the actual problem, as...
(lldb) po 0x4f9584
$1 = 5215620 DataUtils
(lldb) print (BOOL)[$1 respondsToSelector:#selector(allocWithZone:)]
(BOOL) $2 = YES
So I'm definitely missing something... I compared to assembly generated by a [super allocWithZone:NULL] method in an empty class... almost identical except for the functions called have different names (maybe just using different symbols, no idea, can't read it that well).
Any ideas? I can use class_getClassMethod on the superclass and call the IMP directly, but I'm trying to be reasonable in my abuse of the runtime :)
Alright, this wasn't actually that tricky once I recalled that the meta class contains all of the method information for a Class instance obtained via -[self class] or +[self] -> thanks http://www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html
This error occurred because I was asking the runtime to look up the method in NSObject's set of instance methods, which obviously doesn't contain allocWithZone: . The mistake in the error log presumably originated because the receiver was a metaclass instance, and Apple has their interns implement error logs.
so while with a normal instance method call via objc_msgSendSuper, you would pass a metaclass instance as objc_super.super_class, to invoke a class method, the metaclass itself is needed (everything is one level up).
Example, and a diagram that helped me understand this - (http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html)
struct objc_super mySuper;
mySuper.receiver = theClassToInit; //this is our receiver, no doubt about it
//either grab the super class and get its metaclass
mySuper.super_class = object_getClass( class_getSuperclass( theClassToInit ) );
//or grab the metaclass, and get its super class, this is the exact same object
mySuper.super_class = class_getSuperclass( object_getClass( theClassToInit ) );
Then the message can be resolved correctly. Makes perfect sense now that I started paying attention :P
Anyways, now that I found my mistake I feel like I've leveled up my Objc runtime understanding. I was also able to fix an architectural mistake made two years ago by someone I never met without having to modifying and re-test dozens of classes across 3 projects and 2 static libraries (God I love Objective-C). Replacing the #synchronized construct with a simple function call also halved the compiled code size of those methods. As a bonus, all our singleton accessors are now (more) threadsafe, because the performance cost for doing so is now negligible. Methods which naively re-fetched the singleton object multiple times (or in loops) have seen a huge speedup now that they don't have to acquire and release a mutex multiple times per invocation. All in all I'm very happy it all worked as I'd hoped.
I made a "normal" Objective-C method for this on a category of NSObject, which will work for both instance and Class objects to allow you to invoke a superclass's implementation of a message externally. Warning: This is only for fun, or unit tests, or swizzled methods, or maybe a really cool game.
#implementation NSObject (Convenience)
-(id)performSelector:(SEL)selector asClass:(Class)class
{
struct objc_super mySuper = {
.receiver = self,
.super_class = class_isMetaClass(object_getClass(self)) //check if we are an instance or Class
? object_getClass(class) //if we are a Class, we need to send our metaclass (our Class's Class)
: class //if we are an instance, we need to send our Class (which we already have)
};
id (*objc_superAllocTyped)(struct objc_super *, SEL) = (void *)&objc_msgSendSuper; //cast our pointer so the compiler can sort out the ABI
return (*objc_superAllocTyped)(&mySuper, selector);
}
so
[self performSelector:#selector(dealloc) asClass:[self superclass]];
would be equivalent to
[super dealloc];
Carry on runtime explorers! Don't let the naysayers drag you into their land of handwaving and black magik boxes, it's hard to make uncompromisingly awesome programs there*.
*Please enjoy the Objective-C runtime responsibly. Consult with your QA team for any bugs lasting more than four hours.