zoukankan      html  css  js  c++  java
  • iOS开发-线程安全-09-多线程

      1 返回主页
      2 GarveyCalvin
      3 
      4 程序人生-改变未来
      5 
      6 博客园
      7 首页
      8 新随笔
      9 联系
     10 订阅
     11 管理
     12 随笔- 29  文章- 29  评论- 43 
     13 iOS开发-多线程开发之线程安全篇
     14 
     15 前言:一块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源,比如多个线程访问同一个对象、同一个变量、同一个文件和同一个方法等。因此当多个线程访问同一块资源时,很容易会发生数据错误及数据不安全等问题。因此要避免这些问题,我们需要使用“线程锁”来实现。
     16 
     17  
     18 
     19 本文主要论述IOS创建锁的方法总结,如果大家对多线程编程技术这一块不熟悉,我建议你们先去看我的另一篇文章”iOS开发-多线程编程技术(Thread、Cocoa operations、GCD)“
     20 
     21  
     22 
     23 一、使用关键字
     24 
     25 1)@synchronized(互斥锁)
     26 
     27 优点:使用@synchronized关键字可以很方便地创建锁对象,而且不用显式的创建锁对象。
     28 
     29 缺点:会隐式添加一个异常处理来保护代码,该异常处理会在异常抛出的时候自动释放互斥锁。而这种隐式的异常处理会带来系统的额外开销,为优化资源,你可以使用锁对象。
     30 
     31 二、“Object-C”语言
     32 
     33 1)NSLock(互斥锁)
     34 
     35 2)NSRecursiveLock(递归锁)
     36 
     37 条件锁,递归或循环方法时使用此方法实现锁,可避免死锁等问题。
     38 
     39 3)NSConditionLock(条件锁)
     40 
     41 使用此方法可以指定,只有满足条件的时候才可以解锁。
     42 
     43 4)NSDistributedLock(分布式锁)
     44 
     45 在IOS中不需要用到,也没有这个方法,因此本文不作介绍,这里写出来只是想让大家知道有这个锁存在。
     46 
     47 如果想要学习NSDistributedLock的话,你可以创建MAC OS的项目自己演练,方法请自行Google,谢谢。
     48 
     49 三、C语言
     50 
     51 1)pthread_mutex_t(互斥锁)
     52 
     53 2)GCD-信号量(“互斥锁”)
     54 
     55 3)pthread_cond_t(条件锁)
     56 
     57  
     58 
     59 线程安全 —— 锁
     60 
     61 一、使用关键字:
     62 
     63 1)@synchronized
     64 
     65 复制代码
     66 // 实例类person
     67 Person *person = [[Person alloc] init];
     68 
     69 // 线程A
     70 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     71     @synchronized(person) {
     72         [person personA];
     73         [NSThread sleepForTimeInterval:3]; // 线程休眠3秒
     74     }
     75 });
     76 
     77 // 线程B
     78 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     79     @synchronized(person) {
     80         [person personB];
     81     }
     82 });
     83 复制代码
     84 关键字@synchronized的使用,锁定的对象为锁的唯一标识,只有标识相同时,才满足互斥。如果线程B锁对象person改为self或其它标识,那么线程B将不会被阻塞。你是否看到@synchronized(self) ,也是对的。它可以锁任何对象,描述为@synchronized(anObj)。
     85 
     86  
     87 
     88 二、Object-C语言
     89 
     90 1)使用NSLock实现锁
     91 
     92 复制代码
     93 // 实例类person
     94 Person *person = [[Person alloc] init];
     95 // 创建锁
     96 NSLock *myLock = [[NSLock alloc] init];
     97 
     98 // 线程A
     99 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    100     [myLock lock];
    101     [person personA];
    102     [NSThread sleepForTimeInterval:5];
    103     [myLock unlock];
    104 });
    105 
    106 // 线程B
    107 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    108     [myLock lock];
    109     [person personB];
    110     [myLock unlock];
    111 }); 
    112 复制代码
    113 程序运行结果:线程B会等待线程A解锁后,才会去执行线程B。如果线程B把lock和unlock方法去掉之后,则线程B不会被阻塞,这个和synchronized的一样,需要使用同样的锁对象才会互斥。
    114 
    115 NSLock类还提供tryLock方法,意思是尝试锁定,当锁定失败时,不会阻塞进程,而是会返回NO。你也可以使用lockBeforeDate:方法,意思是在指定时间之前尝试锁定,如果在指定时间前都不能锁定,也是会返回NO。
    116 
    117 注意:锁定(lock)和解锁(unLock)必须配对使用
    118 
    119  
    120 
    121 2)使用NSRecursiveLock类实现锁 
    122 
    123 复制代码
    124 // 实例类person
    125 Person *person = [[Person alloc] init];
    126 // 创建锁对象
    127 NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init];
    128 
    129 // 创建递归方法
    130 static void (^testCode)(int);
    131 testCode = ^(int value) {
    132     [theLock tryLock];
    133     if (value > 0)
    134     {
    135         [person personA];
    136         [NSThread sleepForTimeInterval:1];
    137         testCode(value - 1);
    138     }
    139     [theLock unlock];
    140 };
    141 
    142 //线程A
    143 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    144     testCode(5);
    145 });
    146 
    147 //线程B
    148 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    149     [theLock lock];
    150     [person personB];
    151     [theLock unlock];
    152 });
    153 复制代码
    154 如果我们把NSRecursiveLock类换成NSLock类,那么程序就会死锁。因为在此例子中,递归方法会造成锁被多次锁定(Lock),所以自己也被阻塞了。而使用NSRecursiveLock类,则可以避免这个问题。
    155 
    156  
    157 
    158 3)使用NSConditionLock(条件锁)类实现锁:
    159 
    160 使用此方法可以创建一个指定开锁的条件,只有满足条件,才能开锁。
    161 
    162 复制代码
    163 // 实例类person
    164 Person *person = [[Person alloc] init];
    165 // 创建条件锁
    166 NSConditionLock *conditionLock = [[NSConditionLock alloc] init];
    167 
    168 // 线程A
    169 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    170     [conditionLock lock];
    171     [person personA];
    172     [NSThread sleepForTimeInterval:5];
    173     [conditionLock unlockWithCondition:10];
    174 });
    175 
    176 // 线程B
    177 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    178     [conditionLock lockWhenCondition:10];
    179     [person personB];
    180     [conditionLock unlock];
    181 });
    182 复制代码
    183 线程A使用的是lock方法,因此会直接进行锁定,并且指定了只有满足10的情况下,才能成功解锁。
    184 
    185 unlockWithCondition:方法,创建条件锁,参数传入“整型”。lockWhenCondition:方法,则为解锁,也是传入一个“整型”的参数。
    186 
    187  
    188 
    189 三、C语言
    190 
    191 1)使用pthread_mutex_t实现锁
    192 
    193 注意:必须在头文件导入:#import <pthread.h>
    194 
    195 复制代码
    196 // 实例类person
    197 Person *person = [[Person alloc] init];
    198 
    199 // 创建锁对象
    200 __block pthread_mutex_t mutex;
    201 pthread_mutex_init(&mutex, NULL);
    202 
    203 // 线程A
    204 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    205     pthread_mutex_lock(&mutex);
    206     [person personA];
    207     [NSThread sleepForTimeInterval:5];
    208     pthread_mutex_unlock(&mutex);
    209 });
    210 
    211 // 线程B
    212 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    213     pthread_mutex_lock(&mutex);
    214     [person personB];
    215     pthread_mutex_unlock(&mutex);
    216 });
    217 复制代码
    218 实现效果和上例的相一致
    219 
    220   
    221 
    222 2)使用GCD实现“锁”(信号量)
    223 
    224 GCD提供一种信号的机制,使用它我们可以创建“锁”(信号量和锁是有区别的,具体请自行百度)。
    225 
    226 复制代码
    227 // 实例类person
    228 Person *person = [[Person alloc] init];
    229 
    230 // 创建并设置信量
    231 dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    232 
    233 // 线程A
    234 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    235     dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    236     [person personA];
    237     [NSThread sleepForTimeInterval:5];
    238     dispatch_semaphore_signal(semaphore);
    239 });
    240 
    241 // 线程B
    242 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    243     dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    244     [person personB];
    245     dispatch_semaphore_signal(semaphore);
    246 });
    247 复制代码
    248 效果也是和上例介绍的相一致。
    249 
    250 我在这里解释一下代码。dispatch_semaphore_wait方法是把信号量加1,dispatch_semaphore_signal是把信号量减1。
    251 
    252 我们把信号量当作是一个计数器,当计数器是一个非负整数时,所有通过它的线程都应该把这个整数减1。如果计数器大于0,那么则允许访问,并把计数器减1。如果为0,则访问被禁止,所有通过它的线程都处于等待的状态。
    253 
    254  
    255 
    256 3)使用POSIX(条件锁)创建锁
    257 
    258 复制代码
    259 // 实例类person
    260 Person *person = [[Person alloc] init];
    261 
    262 // 创建互斥锁
    263 __block pthread_mutex_t mutex;
    264 pthread_mutex_init(&mutex, NULL);
    265 // 创建条件锁
    266 __block pthread_cond_t cond;
    267 pthread_cond_init(&cond, NULL);
    268 
    269 // 线程A
    270 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    271     pthread_mutex_lock(&mutex);
    272     pthread_cond_wait(&cond, &mutex);
    273     [person personA];
    274     pthread_mutex_unlock(&mutex);
    275 });
    276 
    277 // 线程B
    278 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    279     pthread_mutex_lock(&mutex);
    280     [person personB];
    281     [NSThread sleepForTimeInterval:5];
    282     pthread_cond_signal(&cond);
    283     pthread_mutex_unlock(&mutex);
    284 });
    285 复制代码
    286 效果:程序会首先调用线程B,在5秒后再调用线程A。因为在线程A中创建了等待条件锁,线程B有激活锁,只有当线程B执行完后会激活线程A。
    287 
    288 pthread_cond_wait方法为等待条件锁。
    289 
    290 pthread_cond_signal方法为激动一个相同条件的条件锁。
    291 
    292  
    293 
    294  
    295 
    296 简单总结:
    297 
    298 一般来说,如果项目不大,我们都会偷点懒,直接使用关键字@synchronized建立锁,懒人方法。其次可以使用苹果提供的OC方法,最后才会去使用C去建立锁。
    299 
    300  
    301 
    302  
    303 
    304  
    305 
    306  
    307 
    308 本文参考文章:
    309 
    310 iOS多线程开发(四)---线程同步
    311 
    312 Objective-C中不同方式实现锁(一)
    313 
    314 信号量与互斥锁
    315 
    316  
    317 
    318  
    319 
    320  
    321 
    322 博文作者:GarveyCalvin
    323 
    324 博文出处:http://www.cnblogs.com/GarveyCalvin/
    325 
    326 本文版权归作者和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作!
    327 
    328  
    329 
    330 笔者需要换工作,工作地点:广州,职位:ios开发工程师,如有介绍的请推荐一下,谢谢。
    331 分类: IOS开发-Object C, 多线程
    332 标签: IOS, OBJECT-C, 手机开发, 多线程, 互斥锁, 递归锁, 条件锁, 线程安全
    333 绿色通道: 好文要顶 关注我 收藏该文与我联系 
    334 
    335 GarveyCalvin
    336 关注 - 5
    337 粉丝 - 35
    338 +加关注
    339 0
    340 0
    341 (请您对文章做出评价)
    342 « 上一篇:Git-学习笔记(常用命令集合)
    343 » 下一篇:MAC-Zsh安装与使用——终极Shell
    344 posted @ 2015-02-10 14:15 GarveyCalvin 阅读(405) 评论(0) 编辑 收藏
    345 刷新评论刷新页面返回顶部
    346 注册用户登录后才能发表评论,请 登录 或 注册,访问网站首页。
    347 【免费课程】案例:导航条菜单的制作
    348 【推荐】50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
    349 融云,免费为你的App加入IM功能——让你的App“聊”起来!!
    350 
    351 最新IT新闻:
    352 · 小米或于本月内推出超低价手机:399元红米
    353 · 封闭还是开放?Android Wear离iOS究竟有多远
    354 · 平板手机用户最爱看什么?数据统计给出的答案是体育
    355 · Feynman Liang:一年修完50堂MOOC课程的修课狂人
    356 · 独立局部主义精神
    357 » 更多新闻...
    358 
    359 最新知识库文章:
    360 · 图片服务架构演进
    361 · 软件架构师是一个角色,不是一项工作
    362 · 给公司部门设计的SOA架构
    363 · 好代码不值钱
    364 · 关于响应式布局
    365 » 更多知识库文章...
    366 公告
    367 
    368 昵称:GarveyCalvin
    369 园龄:4个月
    370 粉丝:35
    371 关注:5
    372 +加关注
    373 <    2015年3月    >
    374 日    一    二    三    四    五    六
    375 22    23    24    25    26    27    28
    376 1    2    3    4    5    6    7
    377 8    9    10    11    12    13    14
    378 15    16    17    18    19    20    21
    379 22    23    24    25    26    27    28
    380 29    30    31    1    2    3    4
    381 搜索
    382 
    383  
    384  
    385 常用链接
    386 
    387 我的随笔
    388 我的评论
    389 我的参与
    390 最新评论
    391 我的标签
    392 更多链接
    393 随笔分类
    394 
    395 C语言
    396 IOS开发-Object C(20)
    397 IOS开发-Swift(3)
    398 MySQL-数据库(2)
    399 Quartz2D(1)
    400 动画效果(3)
    401 多线程(2)
    402 其它(7)
    403 自动布局(2)
    404 随笔档案
    405 
    406 2015年3月 (1)
    407 2015年2月 (4)
    408 2015年1月 (5)
    409 2014年12月 (13)
    410 2014年11月 (5)
    411 2014年10月 (1)
    412 文章分类
    413 
    414 apple开发者账户
    415 Git使用(1)
    416 IOS类别(6)
    417 MAC类别(2)
    418 科学上网(1)
    419 数据库
    420 英文学习(2)
    421 转载
    422 最新评论
    423 
    424 1. Re:MySQL之终端(Terminal)管理数据库、数据表、数据的基本操作
    425 收藏了 楼主辛苦了
    426 --mesoar
    427 2. Re:iOS开发-正则表达式的使用方法
    428 @董铂然谢谢,目前我也是使用过一小部分的元字符。...
    429 --GarveyCalvin
    430 3. Re:iOS开发-正则表达式的使用方法
    431 写的不错 但我只用过 .*?和(.*?)。
    432 --董铂然
    433 阅读排行榜
    434 
    435 1. MySQL之终端(Terminal)管理数据库、数据表、数据的基本操作(825)
    436 2. iOS开发-多线程编程技术(Thread、Cocoa operations、GCD)(751)
    437 3. iOS开发-UIView之动画效果的实现方法(合集)(741)
    438 评论排行榜
    439 
    440 1. iOS开发-项目的完整重命名方法,图文教程。(11)
    441 2. Git-学习笔记(常用命令集合)(7)
    442 3. iOS开发-自动布局之autoresizingMask使用详解(Storyboard&Code)(6)
    443 推荐排行榜
    444 
    445 1. Git-学习笔记(常用命令集合)(8)
    446 2. iOS开发-多线程编程技术(Thread、Cocoa operations、GCD)(4)
    447 3. iOS开发-Object-C Block的实现方式(4)
    448 Copyright ©2015 GarveyCalvin
    时光见证了成长,还很无知,我想一点点幼稚转为有知!
  • 相关阅读:
    taotao订单系统
    使用JMeter进行一次简单的带json数据的post请求测试
    taotao购物车2 解决购物车本地cookie和服务器redis不同步的问题
    Dubbo入门介绍---搭建一个最简单的Demo框架
    关于地图模糊
    二维纹理 Texture 2D
    TexturePacker
    Unity3D实现3D立体游戏原理及过程,需偏振眼镜3D显
    解决RegexKitLite编译报错
    QualitySettings 3d模型质量显示设置
  • 原文地址:https://www.cnblogs.com/foreveriOS/p/5414960.html
Copyright © 2011-2022 走看看