在学会简单的使用GCD处理多线程之后,我们来再深入了解下GCD对多线程的一些同步控制。
dispatch barriers
在使用 Concurrent Queue 的时候,有时候我们希望队列中的某项任务,能够被串行执行,来避免资源竞争等多线程问题。比如遇到读写问题,这时候我们就需要使用 dispatch barriers。来保证即使在并行队列中,对某个对象的读和写操作,在同一时刻,只有一个可以被执行。这时候就可以用到 dispatch barriers了。下面我们来讨论一下,不同的队列中barriers的使用:
Custom Serial Queue: 在串行队列中,队列都是顺序串行执行,使用barriers没有任何好处。一般来讲我们不需要这么做。
Global Concurrent Queue: 这里虽然是并行队列,但这个队列是全局的,我们不能保证别人没有使用这个队列。对这个队列加barriers,可能会影响到其他模块的功能。所以不建议在这个队列中使用。
Custom Concurrent Queue: 在自定义的并行队列中使用barriers,是比较合适的方式。
所以当我们要做的并行操作,可能存在线程安全问题的时候。我们最好考虑新建自定义并行队列,而不是简单地使用系统提供的 Global Queue。
举一个例子,假设某一个类要管理MyClass这个类型的读写,下面列举这个类的一些相关方法:
1 |
|
dispatch groups
有时候,我们需要在多个并行任务全部完成后,做一些操作,这时候就需要用到 group来管理了。
举一个简单的例子。我有4个任务要使用并发处理,任务4要等待,任务1、2、3完成后执行。同时,任务4不阻塞当前的线程:
1 | - (void)testDispatchGroup{ |
再看另一个需求,还是之前的4个任务。唯一的区别是,任务4除了要等待其他任务完成,还要阻塞当前线程:
1 | - (void)testDispatchGroup{ |
另外,除了使用dispatch_group_async管理要做的任务。还可以使用dispatch_group_enter
、 dispatch_group_leave
组合的方式,手动通知任务完成。如果使用手动管理的话,我们要注意:enter和leave方法,应该是成对出现的
。
dispatch_group_enter(customGroup) : 手动告知customGroup,表示一个任务已经开始执行。
dispatch_group_leave(customGroup) : 手动告知customGroup,表示一个任务已经完成。当所有enter对应的leave方法都执行过后。我们的dispatch_group_notify()
或者dispatch_group_wait()
,就可以接到任务完成的通知。
dispatch semaphore 信号量
当有多个消费者,访问有限的资源的时候,信号量) 可以让我们更好的控制。简单来说,我们通过对信号个数的控制,来达到线程间的同步操作。当信号个数为0的时候,当前线程被阻塞,等待信号量增加,当信号量个数大于0的时候,则线程继续执行。
注意,同步的操作都要小心使用,避免死锁等问题。
另外,根据dispatch_semaphore_wait的返回值,可以用于判断某任务是否超时操作。
1 |
|