• iOS开发信号量的使用


    1、GCD提供了一种信号量机制,我们可以用它来做线程的同步控制。

    信号量的工作机制:
    信号量支持“信号通知”和“等待”两个操作,初始化时会给信号量一个初始整形值,他代表线程可以访问的资源数。信号量被通知,值加一,当一个线程被信号量控制为等待,线程会被阻塞,直到信号量计数值大于0,然后线程会减少这个计数。
    GCD提供了3个信号量操作:

    //创建信号,5是信号总量
    dispatch_semaphore_create(5);
    //发送一个信号,信号量+1
    dispatch_semaphore_signal(semphore)
    //等待信号
    dispatch_semaphore_wait(semphore, DISPATCH_TIME_FOREVER)
    

    2、使用场景

    1、快速创建一个并发控制,和有限资源访问控制。

    - (void)testSemaphore1 {
        //创建计数为1的信号量
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
        //线程A
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
           //等待,如果信号量大于0,那么继续往下执行并减少一个信号量
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            //耗时操作模拟
            [NSThread sleepForTimeInterval:5];
            NSLog(@"线程A=%@", [NSThread currentThread]);
            //信号加1
            dispatch_semaphore_signal(semaphore);
        });
        
        //线程B
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
           //等待,如果信号量大于0,那么继续往下执行并减少一个信号量
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            //耗时操作模拟
            [NSThread sleepForTimeInterval:5];
            NSLog(@"线程B=%@", [NSThread currentThread]);
            //信号加1
            dispatch_semaphore_signal(semaphore);
        });
    }
    

    打印日志:

    2021-03-11 17:31:09.895460+0800 Demo[66780:1352656] 线程A=<NSThread: 0x6000024c83c0>{number = 7, name = (null)}
    2021-03-11 17:31:14.898532+0800 Demo[66780:1352655] 线程B=<NSThread: 0x6000024ffb80>{number = 6, name = (null)}
    

    2、使用信号量实现任务2依赖任务1。任务1和2都是异步提交的

    具体实现:创建信号量并初始化为0,让任务2执行前等待信号,实现对任务2的阻塞。任务1完成后再发送信号,信号量
    值为1,从而任务2获得执行权。

    - (void)testSemaphore2 {
        //创建计数为0的信号量
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        //任务1
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            //耗时操作模拟
            NSLog(@"任务1开始执行");
            [NSThread sleepForTimeInterval:5];
            NSLog(@"任务1执行结束");
            //信号加1
            dispatch_semaphore_signal(semaphore);
        });
        
        //任务2
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
           //等待,如果信号量大于0,那么继续往下执行并减少一个信号量
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            //耗时操作模拟
            NSLog(@"任务2开始执行");
            [NSThread sleepForTimeInterval:5];
            NSLog(@"任务2执行结束");
        });
    }
    

    执行顺序日志:

    2021-03-11 17:50:30.095164+0800 Demo[67625:1373615] 任务1开始执行
    2021-03-11 17:50:35.100431+0800 Demo[67625:1373615] 任务1执行结束
    2021-03-11 17:50:35.100935+0800 Demo[67625:1373613] 任务2开始执行
    2021-03-11 17:50:40.105960+0800 Demo[67625:1373613] 任务2执行结束
    

    3、通过信号量控制线程的最大并发数量

    GCD不像NSOperation 那样具有自带控制线程最大并发数量的机制和参数。不过可以通过信号量机制来控制。
    实现思路:创建信号量,并初始化信号量为想要控制的最大并发数量。然后在每个任务执行前进行P操作【等待】;每个任务执行结束后进行V操作。这样,始终保持信号量的值在5以内。从而实现最大并发数的控制。

    - (void)testSemaphore3 {
        //创建计数为5的信号量
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(5);
        //模拟1000个等待执行的任务,通过信号量控制最大并发任务数量为5
        for(int i = 0; i < 1000; i++) {
            /*任务i*/
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
               //耗时任务i,执行前等待,并减少一个信号量
                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
                //耗时操作模拟
                NSLog(@"任务%d开始执行",i);
                [NSThread sleepForTimeInterval:5];
                NSLog(@"任务%d执行结束",i);
                /*任务i结束,发送信号量释放一个资源*/
                dispatch_semaphore_signal(semaphore);
            });
        }
    }
    

    日志打印 可以发现,执行状态的同时最多有5个

    2021-03-11 17:54:09.127336+0800 Demo[67787:1378009] 任务1开始执行
    2021-03-11 17:54:09.127375+0800 Demo[67787:1378007] 任务3开始执行
    2021-03-11 17:54:09.127375+0800 Demo[67787:1378010] 任务2开始执行
    2021-03-11 17:54:09.127388+0800 Demo[67787:1378008] 任务0开始执行
    2021-03-11 17:54:09.127660+0800 Demo[67787:1378005] 任务4开始执行
    
    2021-03-11 17:54:14.134378+0800 Demo[67787:1378010] 任务2执行结束
    2021-03-11 17:54:14.134472+0800 Demo[67787:1378007] 任务3执行结束
    2021-03-11 17:54:14.134509+0800 Demo[67787:1378009] 任务1执行结束
    2021-03-11 17:54:14.134529+0800 Demo[67787:1378008] 任务0执行结束
    2021-03-11 17:54:14.134544+0800 Demo[67787:1378005] 任务4执行结束
    
    2021-03-11 17:54:14.136361+0800 Demo[67787:1378103] 任务5开始执行
    2021-03-11 17:54:14.136536+0800 Demo[67787:1378104] 任务6开始执行
    2021-03-11 17:54:14.136733+0800 Demo[67787:1378105] 任务7开始执行
    2021-03-11 17:54:14.136641+0800 Demo[67787:1378106] 任务8开始执行
    2021-03-11 17:54:14.136825+0800 Demo[67787:1378107] 任务9开始执行
    
    2021-03-11 17:54:19.140515+0800 Demo[67787:1378103] 任务5执行结束
    2021-03-11 17:54:19.140572+0800 Demo[67787:1378104] 任务6执行结束
    2021-03-11 17:54:19.140769+0800 Demo[67787:1378108] 任务10开始执行
    2021-03-11 17:54:19.140771+0800 Demo[67787:1378109] 任务11开始执行
    2021-03-11 17:54:19.141722+0800 Demo[67787:1378106] 任务8执行结束
    
  • 相关阅读:
    前端切图:自制简易音乐播放器
    SEO那些事:一句代码一键分享网站
    POJ 2553 Tarjan
    POJ 2186 Tarjan
    POJ 1236 Tarjan算法
    POJ 1330 Tarjan LCA、ST表(其实可以数组模拟)
    POJ 1470 Tarjan算法
    POJ 1985 求树的直径 两边搜OR DP
    POJ 3687 拓扑排序
    POJ 3522 Kruskal
  • 原文地址:https://www.cnblogs.com/wjw-blog/p/14519518.html
Copyright © 2020-2023  润新知