简述
含义
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]}
|