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
时间: 2024-10-13 16:15:30

iOS开发-线程安全-09-多线程的相关文章

iOS开发中的gcd多线程tips

iOS开发中的gcd多线程tips 我们经常用到的: dispatch_async(dispatch_get_global_queue(0, 0), ^{ // 处理耗时操作的代码块 //通知主线程刷新 dispatch_async(dispatch_get_main_queue(), ^{ //回调或者说是通知主线程刷新 }); }); 其中main_queue是系统默认的串行队列,global_queue是系统默认的并行队列. 什么是串行队列(Serial)? 创建任意个数的串行队列,每个队

iOS开发中GCD在多线程方面的理解

GCD为Grand Central Dispatch的缩写. Grand Central Dispatch (GCD)是Apple开发的一个多核编程的较新的解决方法.在Mac OS X 10.6雪豹中首次推出,并在最近引入到了iOS4.0. GCD是一个替代诸如NSThread等技术的很高效和强大的技术.GCD完全可以处理诸如数据锁定和资源泄漏等复杂的异步编程问题. GCD可以完成很多事情,但是这里仅关注在iOS应用中实现多线程所需的一些基础知识. 在开始之前,需要理解是要提供给GCD队列的是代

iOS开发项目篇—09新版本特性&#183;分享

iOS开发项目篇—09新版本特性·分享和开始 一.ios开发中图片的加载 图片的加载: [UIImage imageNamed:@"home"];  加载png图片 (一)非retina屏幕 (1)3.5 inch(320 x 480) * home.png (二)retina屏幕 (1)3.5 inch(640 x 960) * [email protected] (2)4.0 inch(640 x 1136) * [email protected](如果home是程序的启动图片,才

iOS开发——实用技术OC篇&amp;多线程整合

多线程整合 本文知识对iOS开发中多线程的一些知识整合,关于一些概念和技术问题并没有过多的介绍,如果你想了解更多请查看笔者之前写的iOS开发之多线程详解(比较完整):但是有部分涉及到之前文章中没有的技术点和常识,比如加锁的方式,面试相关的,还有一些关于GCD的高级用法,希望你能认真看完,或许可以收获到很多! http://www.cnblogs.com/iCocos/p/4553103.html http://www.cnblogs.com/iCocos/p/4553262.html ??先来看

iOS开发之再探多线程编程:Grand Central Dispatch详解

之前关于iOS开发多线程的内容发布过一篇博客,其中介绍了NSThread.操作队列以及GCD,介绍的不够深入.今天就以GCD为主题来全面的总结一下GCD的使用方式.GCD的历史以及好处在此就不做过多的赘述了.本篇博客会通过一系列的实例来好好的总结一下GCD.GCD在iOS开发中还是比较重要的,使用场景也是非常多的,处理一些比较耗时的任务时基本上都会使用到GCD, 在使用是我们也要主要一些线程安全也死锁的东西. 本篇博客中对iOS中的GCD技术进行了较为全面的总结,下方模拟器的截图就是我们今天要介

iOS开发线程和RunLoop

一般来讲,一个线程一次只能执行一个任务,执行完毕后线程就会退出,如果我们需要一个机制让线程能随时处理时间但并不退出,通常的代码逻辑是这样: 这就是 Event Loop框架. runloop实际上就是一个管理其需要处理的事件和消息的对象,并提供了一个入口函数来执行上面Event loop的逻辑.线程执行了这个函数之后,就会一直处于这个函数内部"接受消息->等待->处理"的循环中,知道这个循环结束(例如传入quite消息),函数返回. 在OSX和iOS系统中,提供了两个这样的

iOS 开发线程 gcd

基础知识: 下午9:09 一.基础概念 1.什么是GCD 全称是Grand Central Dispath 纯C语言编写,提供非常多且强大的函数,是目前推荐的多线程开发方法,NSOperation便是基于GCD的封装 2.GCD的优势 1.为多核的并行运算提出了解决方案 2.GCD会自动利用更多的CPU内核,比如 双核,四核 3.GCD自动管理线程的生命周期(创建线程,调度任务,销毁线程) 4.程序员只需告诉GCD想要执行什么任务,不需要编写任何线程管理代码 3.GCD中的两个核心概念 1.任务

iOS开发 - 线程与进程的认识与理解

进程: 进程是指在系统中正在运行的一个应用程序,比如同时打开微信和Xcode,系统会分别启动2个进程; 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内; 线程: 一个进程要想执行任务,必须得有线程(每一个进程至少要有一条线程),是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位; 一个进程(程序)的所有任务都在线程中执行; 一个程序有且只有一个主线程,程序启动时创建(调用main来启动),主线程的生命周期是和应用程序绑定,程序退出时,主线程也停止;

IOS开发笔记_AFN中多线程依赖

我们平常在开发当中很可能会遇到同时开启两个网络请求,然后把资源下载下来后进行合并操作,那么在AFN中我们究竟要怎么做呢,当然,以下可能写出一些个人的封装技巧,有兴趣的朋友可以发继续关注我. #pragma mark -  getter - (NSOperationQueue *)queue { if (!_queue) { _queue = [[NSOperationQueuealloc]init]; } return_queue; } 这里是我个人对AFN的一个封装类,后面会说到 NSOper