Re: How To Safely Invoke a Block
On 21 Nov 2012, at 10:56, Andreas Grosam agro...@onlinehome.de wrote: I've defined a class Foo that defines a block via a property: @property (copy) void (^progressHandler)(RXProgressState progressState, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite); The property is synthesized by the compiler, ARC enabled. The block is usually invoked on a private thread for several times until an action finishes (an asynchronous NSURLConnection). A client of class Foo should be able to set the block property at any time from any thread - that is it should also be able to set the block to NULL. Now, I'm worried about thread safety. First, is it a good measurement to use a property with the atomic attribute? Secondly, I'm invoking the block as follows (from within a NSURLConnectionDelegate method): progress_handler_block_t block; if ( (block=self.progressHandler) != NULL) { block(RXProgressStateStart, 0, self.source.size); } since it appears to me, that if (_progressHandler) { _progressHandler(RXProgressStateStart, 0, self.source.size); } or if (self.progressHandler) { self.progressHandler(RXProgressStateStart, 0, self.source.size); } isn't thread safe. People are making this seem very complicated! You say you're running with ARC, so the way you are doing things is fine if you mark the property as atomic to make sure the contents are not inadvertently released 'during' your call to the accessor. The local reference to the block will retain it after it's returned from the accessor. The only caveat (and I think this is already obvious to you given what you've said) is that the 'old' block might be run instead of the 'new' block if another thread assigns to the property between the block=self.progressHandler and your invocation of the block. Jamie. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
How To Safely Invoke a Block
I've defined a class Foo that defines a block via a property: @property (copy) void (^progressHandler)(RXProgressState progressState, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite); The property is synthesized by the compiler, ARC enabled. The block is usually invoked on a private thread for several times until an action finishes (an asynchronous NSURLConnection). A client of class Foo should be able to set the block property at any time from any thread - that is it should also be able to set the block to NULL. Now, I'm worried about thread safety. First, is it a good measurement to use a property with the atomic attribute? Secondly, I'm invoking the block as follows (from within a NSURLConnectionDelegate method): progress_handler_block_t block; if ( (block=self.progressHandler) != NULL) { block(RXProgressStateStart, 0, self.source.size); } since it appears to me, that if (_progressHandler) { _progressHandler(RXProgressStateStart, 0, self.source.size); } or if (self.progressHandler) { self.progressHandler(RXProgressStateStart, 0, self.source.size); } isn't thread safe. Your comments are welcome! Regards Andreas ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How To Safely Invoke a Block
On 21 Nov 2012, at 10:56, Andreas Grosam agro...@onlinehome.de wrote: I've defined a class Foo that defines a block via a property: @property (copy) void (^progressHandler)(RXProgressState progressState, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite); The property is synthesized by the compiler, ARC enabled. The block is usually invoked on a private thread for several times until an action finishes (an asynchronous NSURLConnection). A client of class Foo should be able to set the block property at any time from any thread - that is it should also be able to set the block to NULL. Now, I'm worried about thread safety. First, is it a good measurement to use a property with the atomic attribute? Not really, as your block may be released (by the setter) between getting the block and invoking it. Secondly, I'm invoking the block as follows (from within a NSURLConnectionDelegate method): progress_handler_block_t block; if ( (block=self.progressHandler) != NULL) { block(RXProgressStateStart, 0, self.source.size); } since it appears to me, that if (_progressHandler) { _progressHandler(RXProgressStateStart, 0, self.source.size); } or if (self.progressHandler) { self.progressHandler(RXProgressStateStart, 0, self.source.size); } isn't thread safe. Your comments are welcome! Grand Central Dispatch is your friend. @implementation MyClass static dispatch_once_t onceToken; static dispatch_queue_t dispatchQueue; typedef (void(^ProgressHandler)(RXProgressState progressState, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite); - (void)setProgressHandler:(ProgressHandler)progressHandler { dispatch_once(onceToken, ^ { dispatchQueue = dispatch_queue_create(RXProgressQueue, DISPATCH_QUEUE_SERIAL); }); dispatch_sync(dispatchQueue, ^() { if (_progressHandler != progressHandler) { [_progressHandler release]; _progressHandler = [progressHandler copy]; } }); } - (void)progressHandler { return _progressHandler; } - (void)callSite { … dispatch_once(onceToken, ^ { dispatchQueue = dispatch_queue_create(RXProgressQueue, DISPATCH_QUEUE_SERIAL); }); dispatch_sync(dispatchQueue, ^() { ProgressHandler handler = [self progressHandler]; handler(…); }); … } Tom Davie ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How To Safely Invoke a Block
On Nov 21, 2012, at 5:09 AM, Tom Davie wrote: On 21 Nov 2012, at 10:56, Andreas Grosam agro...@onlinehome.de wrote: I've defined a class Foo that defines a block via a property: @property (copy) void (^progressHandler)(RXProgressState progressState, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite); The property is synthesized by the compiler, ARC enabled. The block is usually invoked on a private thread for several times until an action finishes (an asynchronous NSURLConnection). A client of class Foo should be able to set the block property at any time from any thread - that is it should also be able to set the block to NULL. Now, I'm worried about thread safety. First, is it a good measurement to use a property with the atomic attribute? Not really, as your block may be released (by the setter) between getting the block and invoking it. An atomic property's synthesized getter does the equivalent of retain plus autorelease. So, the caller can rely on the received value staying valid for the current scope. https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW28 Grand Central Dispatch is your friend. @implementation MyClass static dispatch_once_t onceToken; static dispatch_queue_t dispatchQueue; typedef (void(^ProgressHandler)(RXProgressState progressState, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite); - (void)setProgressHandler:(ProgressHandler)progressHandler { dispatch_once(onceToken, ^ { dispatchQueue = dispatch_queue_create(RXProgressQueue, DISPATCH_QUEUE_SERIAL); }); dispatch_sync(dispatchQueue, ^() { if (_progressHandler != progressHandler) { [_progressHandler release]; _progressHandler = [progressHandler copy]; } }); } - (void)progressHandler { return _progressHandler; } - (void)callSite { … dispatch_once(onceToken, ^ { dispatchQueue = dispatch_queue_create(RXProgressQueue, DISPATCH_QUEUE_SERIAL); }); dispatch_sync(dispatchQueue, ^() { ProgressHandler handler = [self progressHandler]; handler(…); }); … } You are running the block within the dispatch_sync() block, meaning that the queue is monopolized for however long that runs. That's likely undesirable and prone to deadlocks. If you wanted to do something like this, you would declare 'handler' as __block outside of the dispatch_sync(), retrieve it with the dispatch_sync() block, and then call it after that returns. ARC will ensure that it's retained by the implicitly-strong 'handler' variable. However, that's overkill. Regards, Ken ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com