Last active
January 11, 2016 19:29
-
-
Save vigneshr89/58254282cb1a4bd01031 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
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."); | |
}) | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A simple example to illustrate GCD queues and tasks.