I have an OpenGL app that needs to perform some computations in the background before displaying data.
Sequentially, what I’m doing is :
prepareData(calls background thread)_doLongComputation(in background thread, calls_transferToGPU)_transferToGPU(main thread)
Since I’m using synchronized blocks on the same object glData, critical sections shouldn’t be accessed by more than one thread at the same time, but unfortunately this isn’t the case, and I can’t figure out why.
Any ideas?
The important parts of the code are below :
@property (atomic, retain) NSData *glData;
...snip snip...
- (void) _doLongComputation {
@synchronized (glData) {
// Create a buffer (long operation, done in C++)
unsigned long size;
unsigned char* buffer = createBuffer(&size);
// Create NSData to hold it safely
self.glData = [NSData dataWithBytesNoCopy:buffer length:size freeWhenDone:YES];
}
// Don't wand to deal with locking the OpenGL context,
// so we do all the OpenGL-related stuff in the main queue
dispatch_async (dispatch_get_main_queue(), ^{
[self _transferToGPU];
});
}
- (void) _transferToGPU {
@synchronized (glData) {
...snip snip...
// Transfer buffer to GPU
glBufferData(GL_ARRAY_BUFFER,
glData.length,
glData.bytes,
GL_STATIC_DRAW);
// We're done, so set the buffer to nil
self.glData = nil;
}
}
- (void) prepareData {
[self performSelectorInBackground:@selector(_doLongComputation)];
}
I think you should synchronize on self instead.
Synchronizing on a variable conceptually creates an implicit mutex using the address pointed to by that variable. If the variable points to a different object, it will be a different mutex, even if it’s still the same variable in your code. This means that setting glData in your
@synchronized(glData)blocks defeats the purpose of your synchronization attempt.