Description:
I pass my block to async method, and it is called when operation is finished. I would like to decline calling the block before operation is finished. But if I assign nil to the block variable in my class it is called anyway. I debugged it and I see that if I assign nil to block variable1 the variable2 in not nil. The code below illustrates it:
void (^d1)(NSArray *data) = ^(NSArray *data) {};
void (__weak^d2)(NSArray *data) = d1;
d1 = nil;
Output:
(lldb) po d1
<__NSGlobalBlock__: 0x9c22b8>]
(lldb) po d2
<__NSGlobalBlock__: 0x9c22b8>
(lldb) po d1
<nil>
(lldb) po d2
<__NSGlobalBlock__: 0x9c22b8>
The question:
Why block d2 is not nil? Is it copied by value and isn't copied as pointer?
First of all, you should never depend on an object to be deallocated in a particular place. It is always possible for someone else (e.g. an autorelease pool) to hold a reference to it without you knowing. It is not incorrect for an object to be not deallocated in any place.
Okay, to your case: the __NSGlobalBlock__ gives a hint: this is a "global block". In the current implementation of blocks, there are 3 types of block objects: stack blocks (__NSStackBlock__), heap blocks (__NSMallocBlock__), and global blocks (__NSGlobalBlock__).
Blocks that are closures (i.e. that use some local variable from an outer scope) start out as "stack blocks" -- the object structure has automatic storage duration, just like a local variable, and it becomes invalid when it leaves the scope it's defined in. When a stack block is "copied", it gets moved to a dynamically-allocated object on the heap, like all other objects in Objective-C. This is a heap block. It is reference-counted like other objects in Cocoa, and copying it has the same effect as retain.
Blocks that are not closures (which is what the block in your example is) are implemented as "global blocks". Because it does not contain any captured variables, all instances of the block are the same, and thus there just exactly one instance of it in the entire program. It is statically allocated like string literals, and lives for the entire lifetime of the program. It is not reference-counted, and retain, release, and copy on it have no effect. It cannot be deallocated; that is why your weak reference never gets set to nil. A __weak reference only gets set to nil if the object it points to gets deallocated.
d1 is a reference to the block you created, ^(NSArray *data) {};. Once you assign d2 to d1's reference, the reference count on that block increments. When you set d1 to nil, there is still a strong pointer to the block, d2.
Related
As I know setting a variable property when using concurrency or multithreading is not safe but I can't produce a crash with below code.
class Node {
var data = 0
}
var node = Node()
let concurrentQueue = DispatchQueue(label: "queue", attributes: .concurrent)
for i in 0...1000 {
concurrentQueue.async {
node.data = i // Should get crash at this line
}
}
UPDATE1
Thanks #MartinR for pointing out in his comment.
Enable the “Thread Sanitizer” and it'll report an error immediately.
UPDATE2
The code got EXC_BAD_ACCESS KERN_INVALID_ADDRESS crash if changing data to reference type. It doesn't always happen but sometimes it will. For example:
class Data {}
class Node {
var data = Data() // Use reference type instead of value type
}
var node = Node()
let concurrentQueue = DispatchQueue(label: "queue", attributes: .concurrent)
for i in 0...1000 {
concurrentQueue.async {
node.data = Data() // EXC_BAD_ACCESS KERN_INVALID_ADDRESS
}
}
This behavior also happens in Objective-C. Setting object property concurrently will cause crash. But with primitive type, the crash will not happen.
Questions
Does setting value type property concurrently will produce a crash?
If it doesn't produce a crash, what is the difference between setting value type property and setting reference type property?
It's perfect if anyone can also explain why setting reference type property concurrently will produce a crash.
First off
Class value are stored in heap memory while struct/enum value are stored in stack memory and compiler will try to allocate those memory at compile time (according to my first ref and many online answer). You can check using this code:
class MemTest {}
class Node {
var data = MemTest()
}
let node = Node()
let concurrentQueue = DispatchQueue(label: "queue", attributes: .concurrent)
for index in 0...100000 {
concurrentQueue.async {
node.data = MemTest()
withUnsafePointer(to: &node.data) {
print("Node data # \($0)")
}
withUnsafePointer(to: node.data) {
print("Node data value no. \(index) # \($0)")
}
}
How to: run 2 time and check memory address for value changed time 500, switch MemTest between class and struct will show the difference. Struct will show the same while class will show different address between each time.
So changing value type is just like changing address but the the memory blocks will not be restored while changing reference type is not just changing address but also restore and allocate new memory blocks which will cause the program to break.
Secondly
But if running first code block of #trungduc with withUnsafePointer, it will show us that the index var of for loop is allocated on the go and in the heap memory, so why is that?
As mentioned before, compiler will only try to allocate the mem if the value type is calculable at compile time. If the they are not calculable, the value will be allocated in heap memory and stay there till the end of scope (according to my second ref). So may be the explanation here is the system will restored the allocated stack after everything is done - end of scope (This I'm not very sure). So in this case the code will not produce a crash as we know.
My conclusion, the reference type variable's mem will be allocated and restored with no restriction in this case whereas value type variable's mem will be allocated and removed only after the system enter and exit a the scope which contains said variable
Thanks
#Gokhan Topcu for Check section "Memory Management"
#Bruno Rocha for Check section "Heap Allocated Value Types"
Some words
My answer is not very solid and might have lots of grammar and spelling error. All update are appreciated. Thanks in advance
Update
For the part I'm not very sure:
variable index was copied to a new memory address with operator = so it doesn't matter where the scope end, stack will be released after for loop
After some digging, in #trungduc's code, with reference type variable, it will do 3 things:
Allocate new memory for class Data
Reduce reference to old Data stored in node.data, even free old Data if it's no longer referenced
Point node.data to new Data
While for value type it will do 1 thing only:
Point node.data to Integer in stack memory
The major difference is in step 2 where there is a chance the old Data memory is restored
There are possibilities where this scenario will happen with reference type
________Task 1________|________Task 2________
Allocate new Data #1 |
|Allocate new Data #2
Load pointer to old |
Data |
Reduce reference count|
to old Data |
|Load pointer to old
|Data
Free old Data |
|Reduce reference count
|to old Data (!)
|Free old Data (!)
Reference new Data #1 |
|Reference new Data #2
while with value type, this will happen
________Task 1________|________Task 2________
Reference to Integer 1|
|Reference to Integer 2
In the first case we will have various alternative scenarios but in most case, we get a segmentation fault because thread 2 tries to dereference that pointer after thread 1 free it. There might be other issues like memory leaking as we notice, thread 2 might not reduce reference count to Data #1 correctly
Whereas in second case, it's just changing the pointer.
Note
In second case, it will never cause crash on Intel CPU but not guaranteed on other CPUs as well because many CPUs do not promise that doing this will not cause a crash.
Non-atomic doesn't mean that app will crash if multiple threads are using the shared resource.
Atomic Properties
Defining a property as atomic will guarantee that a valid value will be returned. Notice that valid does not always mean correct.
This also does not mean that atomic properties are thread safe. Different threads can attempt to write and read a the same time. One of two values will be returned — the value before the change or the value of the change
Non-Atomic Properties
Non atomic properties has no guarantee regarding the returned value. It can be the correct value, a partially written value or even some garbage value.
It simply means that the final value will not be consistent. You won't know which thread will update the value last.
You can refer the link for more clarification on this.
Apple offers a CPU and GPU Synchronization sample project that shows how to synchronize access to shared resources between CPU and GPU. To do so, it uses a semaphore which is stored in an instance variable:
#implementation AAPLRenderer
{
dispatch_semaphore_t _inFlightSemaphore;
// other ivars
}
This semaphore is then defined in another method:
- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView
{
self = [super init];
if(self)
{
_device = mtkView.device;
_inFlightSemaphore = dispatch_semaphore_create(MaxBuffersInFlight);
// further initializations
}
return self;
}
MaxBuffersInFlight is defined as follows:
// The max number of command buffers in flight
static const NSUInteger MaxBuffersInFlight = 3;
Finally, the semaphore is utilized as follows:
/// Called whenever the view needs to render
- (void)drawInMTKView:(nonnull MTKView *)view
{
// Wait to ensure only MaxBuffersInFlight number of frames are getting processed
// by any stage in the Metal pipeline (App, Metal, Drivers, GPU, etc)
dispatch_semaphore_wait(_inFlightSemaphore, DISPATCH_TIME_FOREVER);
// Iterate through our Metal buffers, and cycle back to the first when we've written to MaxBuffersInFlight
_currentBuffer = (_currentBuffer + 1) % MaxBuffersInFlight;
// Update data in our buffers
[self updateState];
// Create a new command buffer for each render pass to the current drawable
id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
commandBuffer.label = #"MyCommand";
// Add completion hander which signals _inFlightSemaphore when Metal and the GPU has fully
// finished processing the commands we're encoding this frame. This indicates when the
// dynamic buffers filled with our vertices, that we're writing to this frame, will no longer
// be needed by Metal and the GPU, meaning we can overwrite the buffer contents without
// corrupting the rendering.
__block dispatch_semaphore_t block_sema = _inFlightSemaphore;
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer)
{
dispatch_semaphore_signal(block_sema);
}];
// rest of the method
}
What I fail to understand here is the necessity of the line
__block dispatch_semaphore_t block_sema = _inFlightSemaphore;
Why do I have to copy the instance variable into a local variable and mark this local variable with __block. If I just drop that local variable and instead write
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer)
{
dispatch_semaphore_signal(_inFlightSemaphore);
}];
It seems to work as well. I also tried to mark the instance variable with __block as follows:
__block dispatch_semaphore_t _bufferAccessSemaphore;
This compiles with Clang and seems to work as well. But because this is about preventing race conditions I want to be sure that it works.
So the question is why does Apple create that local semaphore copy marked with __block? Is it really necessary or does the approach with directly accessing the instance variable work just as well?
As a side note, the answer to this SO question remarks that marking instance variables with __block can't be done. The answer is according to gcc but why would Clang allow this if it shouldn't be done?
The important semantic distinction here is that when you use the ivar directly in the block, the block takes a strong reference to self. By creating a local variable that refers to the semaphore instead, only the semaphore is captured (by reference) by the block, instead of self, reducing the likelihood of a retain cycle.
As for the __block qualifier, you'd normally use that to indicate that a local variable should be mutable within the referencing block. However, since the semaphore variable is not mutated by the call to signal, the qualifier isn't strictly necessary here. It still serves a useful purpose from a style perspective, though, in the sense that it emphasizes the lifetime and purpose of the variable.
On the topic of why an ivar can be qualified with __block,
why would Clang allow this if it shouldn't be done?
Perhaps exactly because capturing an ivar in a block implies strongly capturing self. With or without a __block qualifier, if you use an ivar in a block, you're potentially running the risk of a retain cycle, so having the qualifier there doesn't create additional risk. Better to use a local variable (which, by the way, could be a __weak reference to self just as easily as a __block-qualified reference to an ivar) to be explicit and safe.
I think warrenm correctly answered your question as to why one would use a local variable rather than the ivar (and its implicit reference to self). +1
But you asked about why a local variable would marked as __block in this case. The author could have done that to make his/her intent explicit (e.g., to indicate the variable will outlive the scope of the method). Or they could have potentially done it for the sake of efficiency (e.g., why make a new copy of the pointer?).
For example, consider:
- (void)foo {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(4);
NSLog(#"foo: %p %#", &semaphore, semaphore);
for (int i = 0; i < 10; i++) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(#"bar: %p %#", &semaphore, semaphore);
[NSThread sleepForTimeInterval:1];
dispatch_semaphore_signal(semaphore);
});
}
}
While these are all using the same semaphore, in the absence of __block, each dispatched block will get its own pointer to that semaphore.
However, if you add __block to the declaration of that local semaphore variable, and each dispatched block will use the same pointer which will be sitting on the heap (i.e. the address of &semaphore will be the same for each block).
It’s not meaningful here, IMHO, where there’s only one block being dispatched, but hopefully this illustrates the impact of __block qualifier on local var. (Obviously, the traditional use of __block qualifier is if you’re changing the value of the object in question, but that’s not relevant here.)
... marking instance variables with __block can't be done [in gcc] ... but why would Clang allow this if it shouldn't be done?
Regarding why no error on __block for ivars, as that referenced answer said, it’s basically redundant. I’m not sure that just because something is redundant that it should be disallowed.
I have some event from C++ written library which works in background thread:
virtual void OnData(const char* data)
{
NSLog(#"Here 'data' string is present %s", data);
#autoreleasepool {
NSString* sData= [NSString stringWithCString:data encoding:NSUTF8StringEncoding];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Here _sometimes_ 'data'(%s) is nil (\0). But sData is always present %#", data, sData);
[callback OnData:sData];
});
};
}
And sometimes I have NULL(I suspect its garbage actually) in dispatch_async block in argument variable. But local NSString variable is always here. Why?
P.S. Do I actually must use #autoreleasepool in this situation?
You have no assurances about the lifespan of the buffer that const char *data was pointing to by the time the async block is performed. The data could be dangling pointer by that point (and should be assumed to be so). It's very dangerous to use C-style pointers in any asynchronous references or outside the context they were originally created.
You should either use memory managed objects (e.g. NSData, NSString, etc.) or, if you insist on using C-style pointers and need to reference this pointer in the asynchronous block, copy the data to your own buffer, use that buffer, and then free it when you're done using that buffer in your asynchronous routine. In this case, you have your sData, so just don't refer to data after that point, and you'll be fine.
P.S. You later ask whether you must use #autoreleasepool in this situation.
In short, in most cases, no additional autorelease pool is needed. Notably, when using Grand Central Dispatch (e.g. dispatch_async), it has its own autorelease pools, so you don't have to create one. And, when your main thread yield back to its run loop, again, it's pool is drained. In short, you only need manually created autorelease pools when instantiating your own NSThread objects.
Having said that, sometimes you will introduce autorelease pools if doing significant memory intensive operations prior to yielding back to the run loop. In that case, you'll add autorelease pools in order to reduce the peak memory usage of the app. But this would not appear to be one of those cases.
If you had something like this:
void CallOnData()
{
char *test = malloc(5 * sizeof(char));
strcpy(test, "test");
OnData(test);
free(test);
}
You should expect data to be "NULL" in the block.
And autorelease is not needed, assuming you're using ARC, which you should be.
I have a basic understanding of weak reference with the blocks. The problem I am facing is,
Whenever I access self inside the block, the retain count of self gets increased by 2, where as when I access self inside the default block(example UIViewAnimation) the retain count for self gets increased by 1.
Just wanted to understand why it is getting increased by 2.
Thanks in advance!
According to Clang source code for generating code of Objective-C blocks.
CGBlocks.cpp
CGDecl.cpp
CGObjC.cpp
Objective-C blocks literal is generated by EmitBlockLiteral function.
llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
LLVM document explains deeply what is Block literal. Anyway this function generates a block descriptor and a copy helper function of the specified block. The copy helper function is for capturing auto variables and self.
buildBlockDescriptor -> buildCopyHelper -> GenerateCopyHelperFunction
In GenerateCopyHelperFunction function, Clang emits objc_storeStrong for each Objective-C object auto variable that will be captured by the block.
for (const auto &CI : blockDecl->captures()) {
...
EmitARCStoreStrongCall(...
So, this line would count up the retain count of self (1 -> 2).
After that, EmitBlockLiteral function emits objc_retain for each Objective-C object auto variable that will be captured by the block, as well.
// Next, captured variables.
for (const auto &CI : blockDecl->captures()) {
...
EmitExprAsInit -> EmitScalarInit -> EmitARCRetain
Therefore this line would count up the retain count of self too (2 -> 3).
I don't know the exact reason. But apparently, there is some reason to retain Objective-C object before capturing object by the block copy helper function.
Using self inside a block, usually creates a cycle which could be the reason why it gets increased by 2. To fix this, you should try using a weak self. Check this question out
capturing self strongly in this block is likely to lead to a retain cycle
Use something like this
__unsafe_unretained typeof(self) weakSelf = self;
If I have an autoreleased object and I need to provide it to a different thread, what is the best way to do so?
Let's say I have an object that is autoreleased in thread 0. I tell thread 1 about this object and it retains it because it needs it. Later then it's done, it releases it. No problem. When thread 0 runs again and empties its autorelease pool, it sees the retain count is 1 and because it's an autoreleased object it deallocs. Everything is fine, therefore threads don't matter. Right?
By the way this was originally an interview question. The interviewer insisted that an autoreleased object cannot be given to another thread. He seemed almost angry about it. More and more in tech interviews, I encounter ppl who believe they know everything.
You should not pass autoreleased object directly to other thread.
in this code
id _sharedVariable; // ivar
NSConditionLock *_lock;
- (void)thread1
{
id objectNeedToPass = [[NSObject new] autorelease];
[_lock lock];
_sharedVariable = objectNeedToPass;
[_lock unlockWithCondition:1];
}
- (void)thread2
{
while (true)
{
[_lock lockWithCondition:1];
id objectReceived = [_sharedVariable retain];
[_lock unlockWithCondition:0]
process(objectReceived );
[objectReceived release];
}
}
thread2 may see _sharedVariable hold a released object (and crash)
because it may do this
thread 1 create and autorelease object
thread 1 assign it to the shared variable
thread 1 release the object
object deallocated
thread 2 read the object
thread 2 retain the object - crash
to solve the problem, you should pass a retained object
id _sharedVariable; // ivar
NSConditionLock *_lock;
- (void)thread1
{
id objectNeedToPass = [[NSObject new] autorelease];
[_lock lock];
_sharedVariable = [objectNeedToPass retain];
[_lock unlockWithCondition:1];
}
- (void)thread2
{
while (true)
{
[_lock lockWithCondition:1];
id objectReceived = _sharedVariable;
[_lock unlockWithCondition:0]
process(objectReceived );
[objectReceived release];
}
}
however, this may cause memory leak if second thread failed to release the object and make code hard to maintain (retain/release are hard to balance)
There is nothing to worry about at all as long as you are following the normal Cocoa memory management rules. Every single way of "providing it to a different thread" will work fine as long as you are following the rules.
Pretty much any time you "provide something to a different thread", it is asynchronous (unless you are using locks to do synchronous cross-thread execution or something). Which means that the other thread may (and will likely) use it after the current function on this thread has gone out of scope. Any time you store an object that needs to outlive the current execution, it needs to be retained. If you are storing it in an instance variable or global variable directly, then you are responsible for retaining it, according to the memory management rules. If you are storing it in some kind of container object, then that object is responsible for retaining it. So pretty much if you follow the rules, there is nothing to worry about.
Let's consider a common way that people execute things on another thread, with -performSelector:onThread:withObject:waitUntilDone:. If waitUntilDone is false, this function stores the receiver, selector, and argument in some kind of object to wait until the other thread is ready to execute it. Therefore, this function must be responsible for retaining the receiver and object when it places it into this structure, and releasing it when the structure is destroyed. And indeed it does -- if you read the pre-ARC documentation for the method, it says "This method retains the receiver and the arg parameter until after the selector is performed."
So basically the memory management rules are sufficient -- if you store the object in an instance variable, you need to retain it. If you pass it to some other function, then it's their job to take care of it.
Don't. Pass an owning reference to the other thread. The other thread will take ownership of the object and release it when done with it.
With autoreleased objects, you can't tell when the sending threads autorelease pool will be drained, and can't be sure if it will be drained before the receiving thread gets it.