美文网首页
由浅至深理解iOS GCD (一) -- Semaphore的基

由浅至深理解iOS GCD (一) -- Semaphore的基

作者: MacPu | 来源:发表于2017-01-03 19:09 被阅读430次

    前言:

    本系列会由浅至深的讲解iOS Dispatch的用法和实现原理,从最基本的概念到使用方法,再到实现原理,有时也会自己动手实现其中的某些功能。在讲到一些基本概念和API介绍时,我会尽量用Apple的官方文档来解释,我认为这样最为准确,如果有已经看过Apple文档的同学可以跳步这个部分,直接看扩展部分。

    Dispatch Semaphore

    单从字面上理解就是信号量的意思,他主要的作用在于处理多线程任务资源访问的问题,我有时候也用于上锁和解锁的问题。以下附上Apple的官方解释:

    You can use a dispatch semaphore to regulate the number of tasks allowed to simultaneously access a finite resource. For example, each application is given a limited number of file descriptors to use. If you have a task that processes large numbers of files, you do not want to open so many files at one time that you run out of file descriptors. Instead, you can use a semaphore to limit the number of file descriptors in use at any one time by your file-processing code.

    你可以使用dispatch semaphore来调节同时访问有限资源的任务个数。比如,没有程序只能使用有限数量的文件描述符(fd)。如果你有一个任务需要处理大量的文件,但是你又不想同时打开太多的文件而耗尽fd,这时你就可以在你的文件处理代码中用semaphore来限制使用fd的个数。

    A dispatch semaphore works like a traditional semaphore, except that when the resource is available, it takes less time to acquire a dispatch semaphore. The reason is that Grand Central Dispatch does not call into the kernel for this particular case. It calls into the kernel only when the resource is not available and the system needs to park your thread until the semaphore is signaled.

    Dispatch semaphore和传统信号量工作原理类似。但是在资源可用的情况下,使用GCD semaphore将会消耗较少的时间,因为在这种情况下GCD不会调用内核,只有在资源不可用的时候才会调用内核,并且系统需要停在你的线程里,直到发出这个信号。

    GCD Semaphore的API介绍

    dispatch_semaphore_create
    dispatch_semaphore_t dispatch_semaphore_create(long value);
    

    Creates new counting semaphore with an initial value.
    Passing zero for the value is useful for when two threads need to reconcile the completion of a particular event. Passing a value greater than zero is useful for managing a finite pool of resources, where the pool size is equal to the value.
    When your application no longer needs the semaphore, it should call dispatch_release to release its reference to the semaphore object and ultimately free its memory.

    创建一个具有初始值的计数信号量。如果你有两个线程共同完成某一项工作时,你可以使用一个初始值为0的semaphore。如果你需要管理一个有限的资源池时,你使用一个初始值为资源池的大小的Semaphore。如果你不在使用这个Semaphore时,你应该使用dispatch_release销毁semaphore对象并且释放他的内存。(在ARC模式下不需要,系统会自动释放)

    Parameters

    value:
    The starting value for the semaphore. Do not pass a value less than zero.

    信号量的起始值,必须传一个大于等于0的值,否则返回NULL对象。

    Return

    The newly created semaphore, or NULL on failure.

    dispatch_semaphore_wait
    long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
    

    Waits for (decrements) a semaphore.
    Decrement the counting semaphore. If the resulting value is less than zero, this function waits for a signal to occur before returning.

    等待一个semaphore,或者是减少semaphore的计数。每次会执行会将计数器-1.如果减完之后计数器小于0的话,会阻塞在当前线程直到接收到信号。

    Parameters

    timeout:When to timeout (see dispatch_time). The constants DISPATCH_TIME_NOW and DISPATCH_TIME_FOREVER are available as a convenience.

    设置超时,详情见dispatch_time。也可以使用常量 DISPATCH_TIME_NOW 和 DISPATCH_TIME_FOREVER。DISPATCH_TIME_NOW可以理解为非阻塞型的等待(就是不等待)。DISPATCH_TIME_FOREVER就是会一直等待,直到收到信号。

    Return

    Returns zero on success, or non-zero if the timeout occurred.

    返回0就是成功,返回非0就是超时。

    dispatch_semaphore_signal
    long dispatch_semaphore_signal(dispatch_semaphore_t dsema);
    

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

    发送信号,或者增加一个信号量的计数。如果增加之前的值小于0,则将会唤起一个在dispatch_semaphore_wait中等待的线程。(如果有多个线程在等待,iOS会根据线程的优先级来判断具体唤醒哪个线程)。

    注意事项:

    Dispatch Semaphore的用法相对简单,只要注一点就可以了。就是如果semaphore正在wait状态,也就是正在执行dispatch_semaphore_wait操作,这时释放Semaphore的内存会程序会Crash。

    GCD Semaphore 的使用

    GCD Semaphore非常简单,很好理解也很好上手。

    案例 多线程处理文件描述符:

    假如我们在设计socket通信模块或者是文件系统,为了防止数据错乱,我们不允许多线程同时往一个socket或者一个文件里面写数据。所以我们使用Semaphore添加限制。

    - (void)sendData:(dispatch_data_t)data overPipeline:(dispatch_io_t)pipeline callback:(void (^)(NSError *))callback
    {
        if(!_semaphore){
          // 初始化信号量,
            _semaphore = dispatch_semaphore_create(1);
        }
    
        // 等待信号量
        dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
    
        dispatch_io_write(pipeline, 0, data, _writeQueue, ^(bool done, dispatch_data_t data, int _errno){
    
          // 写完了,发送信号让下一个等待的线程进行写的操作。
            dispatch_semaphore_signal(_semaphore);
    
            if (done && callback){
                callback(_errno == 0 ? nil : [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:_errno userInfo:nil]);
            }
        });
    }
    

    相关文章

      网友评论

          本文标题:由浅至深理解iOS GCD (一) -- Semaphore的基

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