Home What is DispatchSemaphore and how to use it
Post
Cancel

What is DispatchSemaphore and how to use it

DispatchSemaphore

Have you ever ran into issue where you want a code to be accessed by one thread at a time? DispatchSemaphore give you this abilty in vary clean way!

Example

Imagen that you have a code to get the token from the server when it’s not there as in the code below:

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
class TokenUpdater {
  var token: String?
   
  func update() {
    DispatchQueue.global().async {
      self.getToken()
    }
  }
   
  private func getToken() {
    guard token == nil else {
      print("token is there")
      return
    }
    print("token not found getting a new token")
    callServerToGetToken()
    print("update token")
    updateToken()
  }
   
  private func updateToken() {
    token = "thisisatokenalongtokenbewbew"
  }
   
  private func callServerToGetToken() {
    sleep(3) // mock the server delay
  }
}

By calling the update() methode in the code above you will request the token if it’s not there.

In the real life case, the update token will be called from multiple places, If you are on the profle screen we will call multiple APIs and each one of them will call update token to make sure that the token is there so, let’s see how it will behave if we have multiple calls

1
2
3
4
5
6
tokenUpdater.update()
tokenUpdater.update()
tokenUpdater.update()
tokenUpdater.update()
tokenUpdater.update()
tokenUpdater.update()

The code above will print out:

1
2
3
4
5
6
7
8
9
10
11
12
token not found getting a new token
token not found getting a new token
token not found getting a new token
token not found getting a new token
token not found getting a new token
token not found getting a new token
update token
update token
update token
update token
update token
update token

Did you see what happend? all the APIs called the get new token API! So 6 times the get token API got called which is wrong! We should get the token once and then use it for the other APIs.

Fixing the issue

To fix this issue DispatchSemaphore come to rescue! DispatchSemaphore has three things you should know, value, wait(), and signal().
The value is the number of threads that can access the code at a time. wait() will make the thread wait until signal() get called.

To see how this work, let’s modify the previous code to have DispatchSemaphore.

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
class TokenUpdater {
  var token: String?
  let semaphore = DispatchSemaphore(value: 1) // We added this
   
  func update() {
    DispatchQueue.global().async {
      self.semaphore.wait() // This
      self.getToken()
      self.semaphore.signal() // And this
    }
  }
   
  func getToken() {
    guard token == nil else {
      print("token is there")
      return
    }
    print("token not found getting a new token")
    callServerToGetToken()
    print("update token")
    updateToken()
  }
   
  func updateToken() {
    token = "thisisatokenalongtokenbewbew"
  }
   
  func callServerToGetToken() {
    sleep(3)
  }
}

Now if you run the code again, you will see the output below:

1
2
3
4
5
6
7
token not found getting a new token
update token
token is there
token is there
token is there
token is there
token is there

As you can see now, one thread is accessing the code at a time!

-❤️~.

To read more about queues you can check the other articles published in this blog under concurrency category.

If you have any questions you can send me a message on Twitter or facebook. Also you can check my Github page or my Apps.

This post is licensed under CC BY 4.0 by the author.