Created
April 21, 2010 10:30
-
-
Save joelreymont/373678 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <tr1/memory> | |
#include <iostream> | |
#include <vector> | |
#include <Block.h> | |
#include <dispatch/dispatch.h> | |
class Data | |
{ | |
public: | |
Data() {} | |
}; | |
typedef std::tr1::shared_ptr<Data> DataRef; | |
typedef std::vector<DataRef> BitsOfData; | |
// Custom block | |
typedef int (^OurBlock)(void); | |
// Generic callback | |
typedef void (^OurCallback)(int status); | |
// Data bits callback | |
typedef void (^DataBitsCallback)(int status, BitsOfData& bits); | |
// Run loop for the thread we want to talk to | |
extern CFRunLoopRef __TheOtherRunLoop; // run loop for the thread we want to talk to | |
// Run synchronously | |
int RunSync(OurBlock block) | |
{ | |
// use an error code to capture the result of the operation | |
__block int status = 0; | |
// and a semaphore to wait until the operation has completed | |
dispatch_semaphore_t sema = dispatch_semaphore_create(0); | |
// enqueue the block on the target run loop | |
CFRunLoopPerformBlock(__TheOtherRunLoop, kCFRunLoopDefaultMode, ^{ | |
// run the block we created previously | |
status = block(); | |
// and signal that we are done | |
dispatch_semaphore_signal(sema); | |
}); | |
// wake up the target run loop | |
CFRunLoopWakeUp(__TheOtherRunLoop); | |
// hold on until we are done above | |
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); | |
// dispose of the semaphore | |
dispatch_release(sema); | |
// and return the error code | |
return status; | |
} | |
// Run asynchronously | |
void RunAsync(OurBlock block, OurCallback callback) | |
{ | |
// callback will run in the caller thread | |
// and use the caller's run loop | |
CFRunLoopRef callbackRunLoop = CFRunLoopGetCurrent(); | |
// enqueue a block on the target run loop | |
CFRunLoopPerformBlock(__TheOtherRunLoop, kCFRunLoopDefaultMode, ^{ | |
// do the work | |
int status = block(); | |
// enqueue a block on the caller's run loop | |
CFRunLoopPerformBlock(callbackRunLoop, kCFRunLoopDefaultMode, ^{ | |
// and make the block invoke the callback and pass the status code | |
callback(status); | |
}); | |
// wake up the caller's run loop | |
CFRunLoopWakeUp(callbackRunLoop); | |
}); | |
// wake up the target run loop | |
CFRunLoopWakeUp(__TheOtherRunLoop); | |
} | |
OurBlock MakeCollectBits(BitsOfData& bits) | |
{ | |
// allocate block on the heap | |
return Block_copy(^{ | |
int status = 0; | |
cout << "We right here!" << endl; | |
// no exceptions can excape the block! | |
try | |
{ | |
DataRef bit1(new Data); | |
bits.push_back(ref1); | |
} | |
catch (...) | |
{ | |
cout << "Unknown exception" << endl; | |
status = -1; | |
} | |
return status; | |
}); | |
} | |
// Synchronous gathering of data bits | |
int CollectBits(BitsOfData& bits) | |
{ | |
// create the block and "capture" bits | |
OurBlock block = MakeCollectBits(bits); | |
// run the block synchronously | |
int status = RunSync(block); | |
// release memory allocated to the block | |
Block_release(block); | |
// we are done | |
return status; | |
} | |
// Asynchronous gathering of data bits | |
void CollectBitsAsync(BitsOfData& bits, DataBitsCallback callback) | |
{ | |
// create a closure as before | |
OurBlock block = MakeCollectBits(bits); | |
// run asynchronously and trigger a callback created on the fly | |
RunAsync(block, ^(int status) { | |
// we are inside "OurCallback" here and need to clean up | |
// the bit collection block first and foremost | |
Block_release(block); | |
// invoke the data bits callback, | |
// giving it what we have collected | |
callback(status, bits); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment