简述
含义
dispatch_semaphore_t/DispatchSemaphore
表示计数信号量。
函数
Objective-C:
dispatch_semaphore_create 
dispatch_semaphore_wait 
dispatch_semaphore_signal 
Swift:
public init(value: Int) 
public func wait()、public func wait(timeout: DispatchTime) -> DispatchTimeoutResult、public func wait(wallTimeout: DispatchWallTime) -> DispatchTimeoutResult 
public func signal() -> Int 
dispatch_semaphore_create
dispatch_semaphore_t dispatch_semaphore_create(long value)
创建计数信号量,value为其起始值。不能传入小于0的值。如果创建失败,则返回NULL。
当两个线程需要协调特定事件的完成时,传入0。
传入大于0的值,在管理有限资源池时是非常有用的,传入的值等于资源池的大小。
当不再需要信号量时,应当调用dispatch_release释放信号量(ARC下不能使用该函数)。
dispatch_semaphore_wait
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout)
返回0,表示成功;否则,表示超时。
减小计数信号量。如果结果值小于0,这个函数在返回之前,会一直等待信号的发生。
dispatch_semaphore_signal
long dispatch_semaphore_signal(dispatch_semaphore_t dsema)
增大计数信号量。如果之前的值小于0,该函数会唤醒一个正在使用dispatch_semaphore_wait函数等待的线程。
适用场景
在上面的dispatch_semaphore_create解释中,已经提到过。
- 对线程的运行进行协调
 
- 管理有限资源池
 
实践
协调线程
也就是控制两个线程中特定事件的完成顺序。应用场景,比如经典的『生产-消费模型』。
在调用dispatch_semaphore_create函数时,必须传入0。
以下面的示例为基础:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | class ViewController: UIViewController {
      override func viewDidLoad() {         super.viewDidLoad()                  Thread.detachNewThreadSelector(#selector(_thread1(arg:)), toTarget: self, with: nil)         Thread.detachNewThreadSelector(#selector(_thread2(arg:)), toTarget: self, with: nil)     }
      @objc private func _thread1(arg: Any?) {         for i in 0..<5 {             print(#function + " \(i)")         }     }
      @objc private func _thread2(arg: Any?) {         for i in 0..<5 {             print(#function + " \(i)")         }     }      }
 
  | 
 
运行上面的代码,结果可能如下:
1 2 3 4 5 6 7 8 9 10
   | _thread2(arg:) 0 _thread1(arg:) 0 _thread2(arg:) 1 _thread1(arg:) 1 _thread2(arg:) 2 _thread1(arg:) 2 _thread2(arg:) 3 _thread1(arg:) 3 _thread2(arg:) 4 _thread1(arg:) 4
 
  | 
 
很明显,两个任务是交错运行的。
为了先执行完_thread2中的任务,再执行_thread1中的任务,使用信号量,就可以这样写:
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
   | class ViewController: UIViewController {          let sema: DispatchSemaphore = DispatchSemaphore(value: 0)
      override func viewDidLoad() {         super.viewDidLoad()                  Thread.detachNewThreadSelector(#selector(_thread1(arg:)), toTarget: self, with: nil)         Thread.detachNewThreadSelector(#selector(_thread2(arg:)), toTarget: self, with: nil)     }
      @objc private func _thread1(arg: Any?) {         self.sema.wait()         for i in 0..<5 {             print(#function + " \(i)")         }     }
      @objc private func _thread2(arg: Any?) {         for i in 0..<5 {             print(#function + " \(i)")         }         self.sema.signal()     }      }
 
  | 
 
运行结果就会是:
1 2 3 4 5 6 7 8 9 10
   | _thread2(arg:) 0 _thread2(arg:) 1 _thread2(arg:) 2 _thread2(arg:) 3 _thread2(arg:) 4 _thread1(arg:) 0 _thread1(arg:) 1 _thread1(arg:) 2 _thread1(arg:) 3 _thread1(arg:) 4
 
  | 
 
管理资源池
也就是协调有限资源的使用。
在创建信号量时,传入的值,要与可用的资源的数量一致。
拿园区小轿车停车为例,停车位属于有限的资源。
当停车位被占用后,其它小轿车是不能再占用该停车位的。
当园区中没有可用的停车位时,其它小轿车就得等待停车位上的小轿车离开后,才能去占用那个停车位。
1 2 3 4 5 6 7 8 9 10 11 12 13
   | class Car: NSObject {     let identifier: String          init(identifier: String) {         self.identifier = identifier     }          override var description: String {         get {             return "{小车[\(self.identifier)]}"         }     } }
 
  | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
   | 
 
  class ParkingSpace: NSObject {     let identifier: String     weak var car: Car? = nil          var available: Bool {         get {             return self.car == nil         }     }          init(identifier: String) {         self.identifier = identifier     }          override var description: String {         get {             return "{停车位[\(self.identifier)]}"         }     } }
 
  | 
 
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
   | class ViewController: UIViewController {          let cars: [Car] = [         Car.init(identifier: "京A 11111"),         Car.init(identifier: "京B 22222"),         Car.init(identifier: "京C 33333"),         Car.init(identifier: "京D 44444"),         Car.init(identifier: "京E 55555"),     ]     let parkingSpaces: [ParkingSpace] = [         ParkingSpace.init(identifier: "001"),         ParkingSpace.init(identifier: "002"),         ParkingSpace.init(identifier: "003"),     ]     let parkingSpaceSemaphore: DispatchSemaphore     let parkingSemaphore: DispatchSemaphore = DispatchSemaphore(value: 1)          override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {         self.parkingSpaceSemaphore = DispatchSemaphore(value: self.parkingSpaces.count)                  super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)     }          required init?(coder aDecoder: NSCoder) {         self.parkingSpaceSemaphore = DispatchSemaphore(value: self.parkingSpaces.count)                  super.init(coder: aDecoder)     }
      override func viewDidLoad() {         super.viewDidLoad()                  for car in self.cars {             Thread.detachNewThreadSelector(#selector(_carParkingThread(arg:)), toTarget: self, with: car)         }     }
      @objc private func _carParkingThread(arg: Any?) {         if let car = arg as? Car {             print("\(car)要来停车啦")             self.parkingSpaceSemaphore.wait()                          self.parkingSemaphore.wait()             var availablePSs: [ParkingSpace] = []             for ps in self.parkingSpaces {                 if ps.available {                     availablePSs.append(ps)                 }             }                          let ps = availablePSs[Int(arc4random_uniform(UInt32(availablePSs.count)))]             ps.car = car             print("\(car)占用了\(ps)")             self.parkingSemaphore.signal()             let ti = 1 + arc4random_uniform(5)             sleep(ti)             ps.car = nil                          print("\(ti)分钟后,\(car)离开了\(ps)")             self.parkingSpaceSemaphore.signal()         }     }      }
 
  | 
 
运行结果可能如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | {小车[京B 22222]}要来停车啦 {小车[京A 11111]}要来停车啦 {小车[京D 44444]}要来停车啦 {小车[京C 33333]}要来停车啦 {小车[京E 55555]}要来停车啦 {小车[京B 22222]}占用了{停车位[003]} {小车[京A 11111]}占用了{停车位[002]} {小车[京D 44444]}占用了{停车位[001]} 1分钟后,{小车[京D 44444]}离开了{停车位[001]} {小车[京C 33333]}占用了{停车位[001]} 4分钟后,{小车[京A 11111]}离开了{停车位[002]} {小车[京E 55555]}占用了{停车位[002]} 5分钟后,{小车[京B 22222]}离开了{停车位[003]} 5分钟后,{小车[京C 33333]}离开了{停车位[001]} 3分钟后,{小车[京E 55555]}离开了{停车位[002]}
 
  |