加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 业界 > 正文

iOS多线程开发:几个容易被忽略的细节

发布时间:2019-06-07 08:19:08 所属栏目:业界 来源:Eternal_Love
导读:一般情况下,iOS开发者只要会使用GCD、@synchronized、NSLock等几个简单的API,就可以应对大部分多线程开发了,不过这样是否真正做到了多线程安全,又是否真正充分利用了多线程的效率优势呢?看看以下几个容易被忽略的细节。 读者写者问题(Readers-writers
副标题[/!--empirenews.page--]

一般情况下,iOS开发者只要会使用GCD、@synchronized、NSLock等几个简单的API,就可以应对大部分多线程开发了,不过这样是否真正做到了多线程安全,又是否真正充分利用了多线程的效率优势呢?看看以下几个容易被忽略的细节。

读者写者问题(Readers-writers problem)

先看下读者写者问题的描述:

有读者和写者两组并发线程,共享同一数据,当两个或以上的读线程同时访问共享数据时不会产生副作用,但若某个写线程和其他线程(读线程或写线程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:

  • 允许多个读者可以同时对共享数据执行读操作;
  • 只允许一个写者写共享数据;
  • 任一写者在完成写操作之前不允许其他读者或写者工作;
  • 写者执行写操作前,应让已有的读者和写者全部退出。

从以上描述可以得知,所谓“读者写者问题”是指保证一个写线程必须与其他线程互斥地访问共享对象的同步问题,允许并发读操作,但是写操作必须和其他读写操作是互斥的。

大部分客户端App做的事情无非就是从网络拉取最新数据、加工数据、展现列表,这个过程中既有拿到最新数据后写入本地的操作,也有上层业务对本地数据的读取操作,因此会牵涉大量的多线程读写操作,很显然,这些基本都属于读者写者问题的范畴[1]。

然而笔者注意到,在遇到多线程读写问题时,多数iOS开发者都会立即想到加锁,或者干脆避免使用多线程,但却少有人会尝试用读者写者问题的思路去进一步提升效率。

以下是实现一个简单cache的示例代码:

  1. //实现一个简单的cache 
  2. - (void)setCache:(id)cacheObject forKey:(NSString *)key { 
  3.     if (key.length == 0) { 
  4.         return; 
  5.     } 
  6.     [_cacheLock lock]; 
  7.     self.cacheDic[key] = cacheObject; 
  8.     ... 
  9.     [_cacheLock unlock]; 
  10.  
  11. - (id)cacheForKey:(NSString *key) { 
  12.     if (key.length == 0) { 
  13.         return nil; 
  14.     } 
  15.     [_cacheLock lock]; 
  16.     id cacheObject = self.cacheDic[key]; 
  17.     ... 
  18.     [_cacheLock unlock]; 
  19.     return cacheObject; 

上述代码用互斥锁来实现多线程读写,做到了数据的安全读写,但是效率却并不是最高的,因为这种情况下,虽然写操作和其他操作之间是互斥的,但同时读操作之间却也是互斥的,这会浪费cpu资源,如何改良呢?不难发现,这其实是个典型的读者写者问题。先看下解决读者写者问题的伪代码:

  1. semaphore ReaderWriterMutex = 1;    //实现读写互斥 
  2. int Rcount = 0;             //读者数量 
  3. semaphore CountMutex = 1;   //读者修改计数互斥 
  4.  
  5. writer(){ 
  6.     while(true){ 
  7.         P(ReaderWriterMutex); 
  8.         write; 
  9.         V(ReaderWriterMutex);    
  10.     } 
  11.      
  12.  
  13. reader(){ 
  14.     while(true){ 
  15.         P(CountMutex); 
  16.         if(Rcount == 0)     //当第一个读者进来时,阻塞写者 
  17.             P(ReaderWriterMutex); 
  18.         ++Rcount; 
  19.         V(CountMutex); 
  20.  
  21.         read; 
  22.  
  23.         P(CountMutex); 
  24.         --Rcount; 
  25.         if(Rcount == 0) 
  26.             V(ReaderWriterMutex);   //当最后一个读者离开后,释放写者 
  27.         V(CountMutex); 
  28.     } 

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读