Channel Synchronization in Objective-C

Our example demonstrates how to synchronize execution across different threads. We’ll use a block to notify the main thread when a background operation is complete. This is similar to using dispatch groups or semaphores in Objective-C.

#import <Foundation/Foundation.h>

// This is the function we'll run in a background thread. The
// completion handler will be used to notify the main thread
// that this function's work is done.
void worker(void (^completion)(void)) {
    NSLog(@"working...");
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"done");
    
    // Call the completion handler to notify that we're done.
    completion();
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // Create a dispatch group to wait for the background work
        dispatch_group_t group = dispatch_group_create();
        
        // Start a worker in a background thread, giving it the group to notify on
        dispatch_group_enter(group);
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            worker(^{
                dispatch_group_leave(group);
            });
        });
        
        // Block until we receive a notification from the worker on the group
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
        
        return 0;
    }
}

To run the program, compile it and then execute:

$ clang -framework Foundation channel-synchronization.m -o channel-synchronization
$ ./channel-synchronization
working...
done

If you removed the dispatch_group_wait line from this program, the program would exit before the worker even started.

In this Objective-C version, we use Grand Central Dispatch (GCD) to manage concurrency. The dispatch_group_t serves a similar purpose to the channel in the original example, allowing us to wait for the background work to complete before the program exits.

The worker function now takes a completion handler block instead of a channel. This block is called when the work is done, similar to sending a value on a channel.

In the main function, we create a dispatch group, start the worker on a background queue, and then wait for it to complete using dispatch_group_wait. This achieves the same synchronization as the original example, but in a more Objective-C idiomatic way.