Re: How To Safely Invoke a Block

2012-11-26 Thread James Montgomerie
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

2012-11-21 Thread Andreas Grosam
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

2012-11-21 Thread Tom Davie

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

2012-11-21 Thread Ken Thomases
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