iOS 信号量semaphore学习总结

常用API:

let semaphore = DispatchSemaphore.init(value: 1)
//初始化信号量 value根据自己的需求来设

semaphore.wait()
// 如果信号量的值>0,就减1,然后往下执行后面的代码
// 如果信号量的值<=0,当前线程就会进入休眠等待,直到信号量的值>0

semaphore.signal()
// 让信号量的值增加1,信号量值不等于零时,前面的等待的代码会执行

信号量semaphore常用场景

1.设置最大并发数
    /**
    * 最大并发
    */
    func concurrent(){
        let semaphore = DispatchSemaphore.init(value: 2)//最大并发数量
        for i in 0...5 {
            DispatchQueue.global().async {
                semaphore.wait()
                print("run task\(i) ---\(Thread.current)")
                sleep(1)//耗时操作
                print("comlete task\(i)")
                semaphore.signal()
            }
        }
        print("mainThread")
    }
输出:
mainThread
run task0 ---<NSThread: 0x2808cfe40>{number = 4, name = (null)}
run task1 ---<NSThread: 0x2808ed780>{number = 5, name = (null)}
comlete task1
comlete task0
run task3 ---<NSThread: 0x2808cee80>{number = 3, name = (null)}
run task2 ---<NSThread: 0x2808e9580>{number = 6, name = (null)}
comlete task3
comlete task2
run task4 ---<NSThread: 0x2808e13c0>{number = 7, name = (null)}
run task5 ---<NSThread: 0x2808e9740>{number = 8, name = (null)}
comlete task4
comlete task5

并发执行2个任务,保证同一时间执行的线程数不超过2

2.保持线程同步,将异步执行任务转换为同步执行任务
    /**
    * semaphore 线程同步
    */
    func semaphoreSync(){
        print("mainThread---\(Thread.current)")
        print("begin")
        let semaphore = DispatchSemaphore.init(value: 0)
        var number = 0
        DispatchQueue.global().async {
            sleep(2)//耗时操作
            print("1---\(Thread.current)")
            number = 100
            semaphore.signal()
        }
        semaphore.wait()//等待异步任务执行完成才可以继续执行
        print("end,number = \(number)")
    }
输出:
mainThread---<NSThread: 0x280ac1f00>{number = 1, name = main}
begin
1---<NSThread: 0x280aaa340>{number = 6, name = (null)}
end,number = 100
3.保证线程安全,为线程加锁

场景:总共有 50 张火车票,有两个售卖火车票的窗口。两个窗口同时售卖火车票,卖完为止。

    /**
    * 非线程安全:不使用 semaphore
    * 初始化火车票数量、卖票窗口(非线程安全)、并开始卖票
    */
    func initTicketStatusNotSave(){
        print("mainThread---\(Thread.current)")
        
        let queue1 = DispatchQueue.init(label: "queue1")//窗口1
        let queue2 = DispatchQueue.init(label: "queue2")//窗口2
        queue1.async {
            self.saleTickeNotSafe()//开始卖票
        }
        queue2.async {
            self.saleTickeNotSafe()//开始卖票
        }
    }
    /**
    * 售卖火车票(非线程安全)
    */
    func saleTickeNotSafe(){
        while true {
            if self.num > 0{
                self.num = self.num - 1
                print("剩余票数:\(self.num), 窗口:\(Thread.current)")
                Thread.sleep(forTimeInterval: 0.2)
            }else{
                print("所有火车票已卖完")
                break
            }
        }
    }
输出:
mainThread---<NSThread: 0x28155d200>{number = 1, name = main}
剩余票数:49, 窗口:<NSThread: 0x281503380>{number = 5, name = (null)}
剩余票数:48, 窗口:<NSThread: 0x281503b40>{number = 6, name = (null)}
剩余票数:46, 窗口:<NSThread: 0x281503380>{number = 5, name = (null)}
剩余票数:46, 窗口:<NSThread: 0x281503b40>{number = 6, name = (null)}
剩余票数:45, 窗口:<NSThread: 0x281503b40>{number = 6, name = (null)}
剩余票数:44, 窗口:<NSThread: 0x281503380>{number = 5, name = (null)}
剩余票数:42, 窗口:<NSThread: 0x281503b40>{number = 6, name = (null)}
.....
剩余票数:0, 窗口:<NSThread: 0x28064aac0>{number = 5, name = (null)}
所有火车票已卖完

可以看到在不考虑线程安全的情况下数据是错乱的。

线程安全(使用 semaphore 加锁)

    /**
    * 使用 semaphore
    * 初始化火车票数量、卖票窗口、并开始卖票
    */
    func initTicketStatusSave(){
        print("mainThread---\(Thread.current)")
        
        let queue1 = DispatchQueue.init(label: "queue1")//窗口1
        let queue2 = DispatchQueue.init(label: "queue2")//窗口2
        self.semaphore = DispatchSemaphore.init(value: 1)//初始化信号量值为1
        queue1.async {
            self.saleTickeSafe()//开始卖票
        }
        queue2.async {
            self.saleTickeSafe()//开始卖票
        }
    }
    /**
    * 售卖火车票
    */
    func saleTickeSafe(){
        while true {
            self.semaphore.wait()//检测信号量:大于0减1继续执行,少于等于0则等待
            if self.num > 0{
                self.num = self.num - 1
                print("剩余票数:\(self.num), 窗口:\(Thread.current)")
                Thread.sleep(forTimeInterval: 0.2)
            }else{
                print("所有火车票已卖完")
                self.semaphore.signal()//信号量加1
                break
            }
            self.semaphore.signal()//信号量加1
        }
    }
输出:
mainThread---<NSThread: 0x28062af40>{number = 1, name = main}
剩余票数:49, 窗口:<NSThread: 0x280666440>{number = 4, name = (null)}
剩余票数:48, 窗口:<NSThread: 0x28064aac0>{number = 5, name = (null)}
剩余票数:47, 窗口:<NSThread: 0x280666440>{number = 4, name = (null)}
剩余票数:46, 窗口:<NSThread: 0x28064aac0>{number = 5, name = (null)}
剩余票数:45, 窗口:<NSThread: 0x280666440>{number = 4, name = (null)}
剩余票数:44, 窗口:<NSThread: 0x28064aac0>{number = 5, name = (null)}
剩余票数:43, 窗口:<NSThread: 0x280666440>{number = 4, name = (null)}
.....
剩余票数:0, 窗口:<NSThread: 0x28064aac0>{number = 5, name = (null)}
所有火车票已卖完

相关简书:
iOS GCD学习总结(一)
iOS GCD学习总结(二)
iOS 线程同步方案学习总结
信号量semaphore学习总结
iOS dispatch_barrier_sync实现多读单写
NSOperation和NSOperationQueue学习总结

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容