由浅至深理解iOS GCD (一) -- Semaphore的基本概念和使用

前言:

本系列会由浅至深的讲解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]);
        }
    });
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容

  • 。。
    Hi杰哥阅读 112评论 0 1
  • 图书馆,她坐在窗边,两扇窗子半开着,窗外的柳树枝丫,乘着风微微摇摆,偶有一缕微风穿过枝丫缝隙闯入窗内,惹得发梢欢快...
    彤彤妹阅读 120评论 0 0
  • A1 小孩已经9岁了,昨天跳舞回来将换下来的衣服装在书包里,忘记拿出来洗了,今天外婆发现了就发火吵她说:“你...
    背包不知圆阅读 179评论 0 0
  • 游戏,学习的真谛是及时反馈与矫正。 地图学习的别称是整体学习。 游戏学习,意味着,从心里来说。是一种主动学习。主动...
    躲进小楼看灯火阅读 465评论 0 0