美文网首页项目搭建
关于dispatch_semaphore_t的浅见

关于dispatch_semaphore_t的浅见

作者: Breezes | 来源:发表于2020-09-15 18:40 被阅读0次
    - (void)semaphoreaTest {
        NSLog(@"semaphore---begin");
        
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        
        dispatch_async(queue, ^{
            [NSThread sleepForTimeInterval:2];
            dispatch_semaphore_signal(semaphore);
        });
        
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        NSLog(@"semaphore---end");
    }
    

    关于dispatch_semaphore_t,网上的文章讲的都是

    image.png image.png

    dispatch_semaphore_wait先会使semaphore count - 1,如果 - 1后的semaphore count >= 0,则放行,不然则阻塞当前线程,而dispatch_semaphore_signal只起到了semaphore count + 1的作用。

    事实是这样吗,dispatch_semaphore_signal官方文档解释是:

    Increment the counting semaphore. If the previous value was less than zero, this function wakes a thread currently waiting in dispatch_semaphore_wait

    意思是dispatch_semaphore_signal会先让semaphore count + 1,如果+1前的semaphore count是 < 0的,则直接唤醒正在dispatch_semaphore_wait中等待的线程,所以我理解的是

    dispatch_semaphore_wait只是起到了通过semaphore count判断是否需要阻塞当前线程并记录当前的线程的作用,当dispatch_semaphore_signal需要唤醒线程时,会根据dispatch_semaphore_wait记录的线程进行唤醒。

    再加一个案例解释,火车票线程安全访问问题:

    - (void)semaphoreThreadSafe {
        [self logCurrentThreadInfo:nil];
        NSLog(@"semaphore---begin");
        
        semaphore = dispatch_semaphore_create(1);
        ticketSurplusCount = 50;
        
        //queue1 1号窗口
        dispatch_queue_t queue1 = dispatch_queue_create("one.window.queue", DISPATCH_QUEUE_SERIAL);
        
        //queue2 2号窗口
        dispatch_queue_t queue2 = dispatch_queue_create("two.window.queue", DISPATCH_QUEUE_SERIAL);
        
        dispatch_async(queue1, ^{
            [self saleTicketSafe];
        });
        dispatch_async(queue2, ^{
            [self saleTicketSafe];
        });
    }
    
    - (void)saleTicketSafe {
        while (1) {
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            if (ticketSurplusCount > 0) {  // 如果还有票,继续售卖
                ticketSurplusCount--;
                NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%ld 窗口:%@", ticketSurplusCount, [NSThread currentThread]]);
                [NSThread sleepForTimeInterval:0.2];
                dispatch_semaphore_signal(semaphore);
            } else { // 如果已卖完,关闭售票窗口
                NSLog(@"所有火车票均已售完");
                
                // 相当于解锁
                dispatch_semaphore_signal(semaphore);
                break;
            }
        }
    }
    

    线程1:1号窗口所在的线程
    线程2:2号窗口所在线程
    semaphore count:信号量计数
    线程1 访问 ticketSurplusCount,通过dispatch_semaphore_waitsemaphore count - 1,此时semaphore count = 0,不需要阻塞线程1
    线程1 还没对ticketSurplusCount访问完成时,线程2 突然也要访问,经过dispatch_semaphore_wait时,semaphore count - 1,此时semaphore count = -1,需要阻塞 线程2线程2变为阻塞(等待)状态;
    ● 此时线程1ticketSurplusCount访问完成,调用dispatch_semaphore_signal使semaphore count + 1,现在的semaphore count = 0,然后由于semaphore count在 + 1前是 < 0 的,所以需要唤醒线程2
    线程2现在可以正常访问了

    相关文章

      网友评论

        本文标题:关于dispatch_semaphore_t的浅见

        本文链接:https://www.haomeiwen.com/subject/ydgfyktx.html