I'm doing some multithreading in Metal, and Thread Sanitizer is tripping up on a "__block id" type (Objective-C) I use in some framework code to collect an identifier returned from a callout block, which is later supplied to a callback block, like:
__block id identifier; //Read-then-write from different threads
id renderer = [self rendererWithCompletionHandler:^{ callback(identifier); }];
dispatch_async(SOME_GLOBAL_QUEUE, ^{
identifier = callout(renderer);
[renderer finish];
});
The API allows any subsystem to do Metal work, then perform any cleanup in the callback without the framework having to understand it, or even what form the identifier takes (frame number, object state, etc). The sample above is heavily simplified, the framework does a lot of setup work to make it convenient to attach to the drawing loop.
The issue is Thread Sanitizer doesn't like the read/write from multiple threads, but how can I efficiently protect "identifier" without doing a lot of extra work, like creating an object? I know the completion handler is strictly ordered after the dispatch_async, but I can't think of how to effectively describe this using GCD or other synchronization primitives. Keep in mind there is an outer loop supplying callout/callback pairs, this occurs at every draw, and pairs may be registered/unregistered after any frame.