2

I'm learning GCD and got question about semaphore. Here is my code:

class ViewController: UIViewController {

    var semaphore: dispatch_semaphore_t! = nil

  override func viewDidLoad() {
    super.viewDidLoad()

    semaphore = dispatch_semaphore_create(0)


    dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
      print("Entering")

      self.semaphoreTask()
      print(self.semaphore.debugDescription)
    }

    semaphoreTask()
     print(semaphore.debugDescription)
  }


  func semaphoreTask() {
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
    for i in 0...1000 {
      print(i)
      if i == 1000 {
        print("i is equal to 10000!")
      }
    }
    dispatch_semaphore_signal(self.semaphore)
  }

If I run this code so nothing from semaphoreTask is printed in the console, but if I change

semaphore = dispatch_semaphore_create(0)

to

semaphore = dispatch_semaphore_create(1)

Everything starts work well.

The question is why should I write dispatch_semaphore_create(1) but not 0?

Thank you!

wm.p1us
  • 2,019
  • 2
  • 27
  • 38

2 Answers2

16

You can use the semaphore in 2 different ways:

  1. To say when work or a resource is ready. In this case you start the semaphore at 0. The creator calls signal when something is ready. The consumer calls wait to wait for the expected item / resource.
  2. To limit the number of concurrent operations / requests / usages. In this case you start the semaphore at a positive value, like 4. The users each call wait and if resource is available they are allowed to continue. If not they are blocked. When each has finished with the resource they call signal.

So, what you see it expected because you're setting the semaphore up as a ready flag but using it as an access limit (because you call wait first).

Wain
  • 118,658
  • 15
  • 128
  • 151
  • Thank you! I got the point. So If I put 0 it wants to execute something but then I say wait and it waits. That was my mistake. Thank you again! – wm.p1us May 11 '16 at 07:15
0

So I corrected my code to show you how I fixed it (thanks to @Wain).

class ViewController: UIViewController {

    var semaphore: dispatch_semaphore_t! = nil

  override func viewDidLoad() {
    super.viewDidLoad()

    semaphore = dispatch_semaphore_create(0)


    dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
      print("Entering")

      self.semaphoreTask()
    }


    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
    semaphoreTask()
  }


  func semaphoreTask() {

    print(semaphore.debugDescription)
    for i in 0...1000 {
      print(i)
      if i == 1000 {
        print("i is equal to 10000!")
      }
    }
    dispatch_semaphore_signal(self.semaphore)
  }
}
wm.p1us
  • 2,019
  • 2
  • 27
  • 38
  • consider printing the thread that is running in `semaphoreTask` so you can see if it's main or the background thread and confirm that main waited for the background thread to complete – Wain May 11 '16 at 08:49