Jeremy W. Sherman

stay a while, and listen

Queue-Specific Data

GCD has a queue-specific storage API accessed using dispatch_queue_{set,get}_specific. This replaces the thread-specific storage provided by pthread_{set,get}_specific that you cannot use with GCD blocks:

static void *sQueueKey_Client = "client";
struct my_client *client = calloc(1, sizeof(*client));
*client = (struct my_client){ .val = 1 };
/* use the unique static address as the key,
 * *not* the address of the string itself */
dispatch_queue_set_specific(q, &sQueueKey_Client, client, free);
dispatch_async(q, ^{
    struct my_client *client =
        dispatch_queue_get_specific(q, &sQueueKey_Client);

Only there’s one new addition to the family: dispatch_get_specific looks up the value in the current context defined by the current queue. This context is broader than the single queue that dispatch_queue_get_specific will search. If a key is not set on the current queue, it will check that queue’s target queue. If it’s not found on that queue, it will move down the line to that queue’s target queue:

dispatch_queue_t io_q = dispatch_queue_create("client_io_queue", 0);
dispatch_set_target_queue(io_q, q);
dispatch_async(io_q, ^{
    /* This will check the current queue (io_q), fail to find
     * the key, then check the target queue (q) and find it. */
    struct my_client *client = dispatch_get_specific(&sQueueKey_Client);

Queue-specific value lookup sounds a lot like chasing the prototype chain in a prototypal object system like JavaScript. In Obj-C, it echoes how method implementation search runs up the inheritance chain to find an implementation for a given message.

It turns out you can abuse this to transform dispatch queue value lookup into the heart of a prototypal object system embedded within Objective-C – where it’s not terribly useful, because Obj-C already has its own object system – or C, where it could be an improvement over hand-writing OOP in C.

I wrote a small, ugly demo of this. It’s available from GitHub as jeremy-w/demo-draft. As it stands, it’s certainly not an improvement over hand-written C OOP, but it did prove an interesting exercise.