Dancing With GCD Group and Barriers
Today we will dinner with GCD Group and barriers features. This article assumes you have already read my previous article Getting Started With GCD in MacRuby & Rubymotion.
Now that we know how to use Grand Central Dispatch to make our application concurrent and parallel, this time I’ll try to show you how GCD makes it easier for us to syncronize blocks and queue tasks.
A dispatch group is a way to monitor a set of block objects for completion. (You can monitor the blocks synchronously or asynchronously depending on your needs.) Groups provide a useful synchronization mechanism for code that depends on the completion of other tasks. Dispatch::Group acts more or less like Thread#join in plain ruby.
Let’s look at some examples to figure out how how Dispatch::Group works:
On this example, Derpina will wait till Derp is back from the kitchen to press the play button. You don’t have to use two queues, both tasks could be executed on the same queue.
How useful are groups on GCD? well let’s take a look into another example, do you know how difficult is to implement Promises and Futures in plain Ruby? well this is how you can implement in MacRuby or Rubymotion:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Now it’s easy to schedule long-running tasks in the background:
1 2 3 4 5 6 7 |
|
this example is brought to you by patrickt (Patrick Thomson) and benstiglitz (Benjamin Stiglitz)
Barriers
I think we have enough of groups, now let’s take a look into something new, barrier were introduced with OS X Lion and iOS 5. Barriers are a specialized version of the Dispatch::Queue#async method. When a block enqueued with barrier_async reaches the front of a private concurrent queue, it waits until all other enqueued blocks to finish executing, at which point the block is executed. No blocks submitted after a call to barrier_async will be executed until the enqueued block finishes. It returns immediately (from Macruby Source code) If the provided queue is not a concurrent private queue, this function behaves identically to the #async function.
let’s look into some code:
1 2 3 4 5 6 |
|
When should we use #barrier_async ? Well barrier_async are pretty useful for example to manipulate data structures which can be read but not written concurrently.
There is a second barrier method, which blocks until the provided task or block is executed. e.g.:
1 2 3 4 5 6 |
|
more barrier example inspired by Mike Ash Let’s imagine that we have a Hash that’s being used as a cache. Hash is thread safe for reading, but doesn’t allow any concurrent access while modifying its contents, not even if the other access is simple reading.”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
To have a better understanding, you should try both versions out (GCD and Ruby Version) one of them will hang, unfortunately the actual MacRuby version is not compiled on Mac OS X Lion, so Dispatch::Queue#barrier_async is not availible, but you can compile it yourself… or ask me on twitter, if I can send you an installer package ;-)
Final
Since one of biggest difference between Android and iOS application is the UI responsiveness, I hope this motivates you to use GCD to improving the user experience of your rubymotion application.