在iOS中,上述代码中的PV原语可以替换成GCD中的信号量API,dispatch_semaphore_t来实现,但是需要额外维护一个readerCount以及实现readerCount互斥访问的信号量,手动实现比较麻烦,封装成统一接口有一定难度。不过好在iOS开发中可以找到现成的读者写者锁:
pthread_rwlock_t
这是一个古老的C语言层面的函数,用法如下:
- // Initialization of lock, pthread_rwlock_t is a value type and must be declared as var in order to refer it later. Make sure not to copy it.
- var lock = pthread_rwlock_t()
- pthread_rwlock_init(&lock, nil)
-
- // Protecting read section:
- pthread_rwlock_rdlock(&lock)
- // Read shared resource
- pthread_rwlock_unlock(&lock)
-
- // Protecting write section:
- pthread_rwlock_wrlock(&lock)
- // Write shared resource
- pthread_rwlock_unlock(&lock)
-
- // Clean up
- pthread_rwlock_destroy(&lock)
接口简洁但是却不友好,需要注意pthread_rwlock_t是值类型,用=赋值会直接拷贝,不小心就会浪费内存,另外用完后还需要记得销毁,容易出错,有没有更高级更易用的API呢?
GCD barrier
dispatch_barrier_async / dispatch_barrier_sync并不是专门用来解决读者写者问题的,barrier主要用于以下场景:当执行某一任务A时,需要该队列上之前添加的所有操作都执行完,而之后添加进来的任务,需要等待任务A执行完毕才可以执行,从而达到将任务A隔离的目的,具体过程如下图所示:

如果将barrier任务之前和之后的并发任务换为读操作,barrier任务本身换为写操作,就可以将dispatch_barrier_async / dispatch_barrier_sync当做读者写者锁来使用了,下面把文初的使用普通锁实现的cache代码,用dispatch_barrier_async重写,做下对比:
- //实现一个简单的cache(使用普通锁)
- - (void)setCache:(id)cacheObject forKey:(NSString *)key {
- if (key.length == 0) {
- return;
- }
- [_cacheLock lock];
- self.cacheDic[key] = cacheObject;
- ...
- [_cacheLock unlock];
- }
-
- - (id)cacheForKey:(NSString *key) {
- if (key.length == 0) {
- return nil;
- }
- [_cacheLock lock];
- id cacheObject = self.cacheDic[key];
- ...
- [_cacheLock unlock];
- return cacheObject;
- }
- //实现一个简单的cache(使用读者写者锁)
- static dispatch_queue_t queue = dispatch_queue_create("com.gfzq.testQueue", DISPATCH_QUEUE_CONCURRENT);
-
- - (void)setCache:(id)cacheObject forKey:(NSString *)key {
- if (key.length == 0) {
- return;
- }
- dispatch_barrier_async(queue, ^{
- self.cacheDic[key] = cacheObject;
- ...
- });
- }
-
- - (id)cacheForKey:(NSString *key) {
- if (key.length == 0) {
- return nil;
- }
- __block id cacheObject = nil;
- dispatch_sync(queue, ^{
- cacheObject = self.cacheDic[key];
- ...
- });
- return cacheObject;
- }
这样实现的cache就可以并发执行读操作,同时又有效地隔离了写操作,兼顾了安全和效率。 (编辑:威海站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|