Skip to content

Instantly share code, notes, and snippets.

@vigneshr89
Last active January 11, 2016 19:29
Show Gist options
  • Save vigneshr89/58254282cb1a4bd01031 to your computer and use it in GitHub Desktop.
Save vigneshr89/58254282cb1a4bd01031 to your computer and use it in GitHub Desktop.
import UIKit
class ViewController: UIViewController {
/***
*
* This method explains a GCD based synchronization mechanism to protect a shared resource.
* In objective C - @synchronized(Object) directive on a object provides similar protection.
* Only one thread can enter a synchronized section on the object being locked.
* The difference between this approach and @synchronized is that the latter is a recursive lock (possible to lock a locked section again, but that many unlocks needed.)
*
***/
@IBAction func tryAgain(sender: AnyObject) {
//Concurrent Queue.
let myConcurrentQ:dispatch_queue_t = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
//Serial Queue. A locker queue.
let lockQueue = dispatch_queue_create("com.test.LockQueue", nil)
/*
4 Async tasks are added to a concurrent Queue in a single thread.
If you want to add 4 sync tasks (they can run simultaneously too) to the queue you need 4 different threads to add them simultaneously.
On a single thread they will automatically run one after another nullifying the purpose of this example.
*/
for _ in 1...4
{
dispatch_async( myConcurrentQ,
{
() -> Void in
print("\(NSThread.currentThread())\n\n");
sleep(UInt32(rand()%2));
/*
Dispatching as Async tasks on a SERIAL queue.
It proves ASYNC tasks are run one after another in a SERIAL queue.
Dispatching them as SYNC has a little danger of ending up in deadlock.
*/
dispatch_async(lockQueue) {
print("Inside the async task\(NSThread.currentThread())\n\n");
self.increaseComponent();
}
});
}
}
var shardComponent: Int = 0;
func sharedComponentInMyView() -> Void
{
print("At \(NSThread.currentThread())value is \(shardComponent)", separator: "", terminator: "\n");
}
func increaseComponent()
{
for i in 1...1000000
{
self.shardComponent = i;
}
self.sharedComponentInMyView();
}
/***
*
* This method explains the behaviour of queues and tasks when added from a single thread.
* SYNC task returns only after the execution is completed. Thus on a SERIAL queue, where only one task is allowed at a time, sync task inside a sync task leads to deadlock.
* ASYNC task is a non blocking call. Thus on a SERIAL queue it does not cause a deadlock but it cannot execute until the executing task is completed.
* SYNC task on a CONCURRENT QUEUE, where more than one task can run at a time, will not casue a deadlock.
*
***/
@IBAction func diffTask(sender: AnyObject) {
let myConcurrentQ:dispatch_queue_t = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
let mySerialQ:dispatch_queue_t = dispatch_queue_create("serial.queue", DISPATCH_QUEUE_SERIAL);
print("Concurrent Queue Demo ::: \n\n")
dispatch_sync(myConcurrentQ) { () -> Void in
print("first sync task");
//Non blocking. Next statement will execute.
dispatch_async(myConcurrentQ) { () -> Void in
print("An async non blocking call; ");
}
sleep(1)
print ("Async call could execute before this statement as it was non bocking and parallel execution was possible. ");
dispatch_sync(myConcurrentQ) { () -> Void in
sleep(1)
print("Thrid sync task. No one can continue till I finish my work!!!");
}
print ("Sync call didn't create a dead lock as another call could execute while this is progressing.But sync call made this statement wait. ");
print(" Note: It is possible to run 2 sync concurrently in a concorrent queue. But you can add sync to concurrent queue simulataneously only from different threads. On a same thread one execute after another. ")
}
print("\n\nSerial Queue Demo ::: \n\n")
dispatch_sync(mySerialQ) { () -> Void in
print("first sync task");
dispatch_async(mySerialQ) { () -> Void in
print("An Async task. It will be excuted only when the first(outer) task is completed. ");
}
sleep(1)
print ("Async task will wait...");
/*
print("Dispatching a sync task inside a sync on serial queue creates dead lock. Becuase serial queue wont let another task untill the first one is completed(Outer). But first task cannot complete untill the sync task (inner) is completed. ")
dispatch_sync(mySerialQ) { () -> Void in
sleep(1)
print("A sync task");
}
print ("This statement can never be executed!");
*/
}
}
/***
*
* This method explains the behaviour of queues and tasks when added from different threads.
* SerialQueue makes sure Task1 is completed before Tasks two is run.
* Concurrent Queue allows the tasks to run simultanesously.
* Sync task returns only after the execution is completed. Async task is a non blocking call.
*
***/
func mutiThreadedBehaviour()
{
let myConcurrentQ:dispatch_queue_t = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
let mySerialQ:dispatch_queue_t = dispatch_queue_create("serial.queue", DISPATCH_QUEUE_SERIAL);
let myConcurrentQ1:dispatch_queue_t = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
let myConcurrentQ2:dispatch_queue_t = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
// The execution order will be Task1 - Task2 - Awake; Proves simulatenous execution.
dispatch_async(myConcurrentQ1) { () -> Void in
dispatch_async(myConcurrentQ, { () -> Void in
print("Task1");
sleep(3);
print("Awake");
})
}
dispatch_async(myConcurrentQ2) { () -> Void in
sleep(1)
dispatch_async(myConcurrentQ, { () -> Void in
print("Task2");
})
}
// The execution order will be Task1 - Awake - Task2; Proves serial execution.
dispatch_async(myConcurrentQ1) { () -> Void in
dispatch_async(mySerialQ, { () -> Void in
print("Task1");
sleep(3);
print("Awake");
})
}
dispatch_async(myConcurrentQ2) { () -> Void in
sleep(1)
dispatch_async(mySerialQ, { () -> Void in
print("Task2");
})
}
}
/***
*
* This method explains custom concurrent queue controls.
* Suspending a thread does not affect the executing task but will not allow any more.
*
***/
@IBAction func explainQueueControls()
{
// It is custom concurrent queue not a global queue. The difference AFAIK is one can add barriers, suspend, resume or cancel the custom created queue but not a global queue.
let myConcurrentQ:dispatch_queue_t = dispatch_queue_create("My Barrier Queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myConcurrentQ) { () -> Void in
dispatch_async(myConcurrentQ, { () -> Void in
print("I will run");
sleep(3);
print("Resuming");
dispatch_resume(myConcurrentQ);
})
dispatch_async(myConcurrentQ, { () -> Void in
print("suspending");
dispatch_suspend(myConcurrentQ);
})
sleep(1);
dispatch_async(myConcurrentQ, { () -> Void in
print("I will only after resuming.");
})
}
}
}
@vigneshr89
Copy link
Author

A simple example to illustrate GCD queues and tasks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment