Objective-C中不同方式实现锁(二)-11-多线程

  1 Objective-C中不同方式实现锁(二)
  2
  3 在上一文中,我们已经讨论过用Objective-C锁几种实现(跳转地址),也用代码实际的演示了如何通过构建一个互斥锁来实现多线程的资源共享及线程安全,今天我们继续讨论锁的一些高级用法。
  4
  5 1.NSRecursiveLock递归锁
  6
  7 平时我们在代码中使用锁的时候,最容易犯的一个错误就是造成死锁,而容易造成死锁的一种情形就是在递归或循环中,如下代码:
  8
  9 1
 10 2
 11 3
 12 4
 13 5
 14 6
 15 7
 16 8
 17 9
 18 10
 19 11
 20 12
 21 13
 22 14
 23 15
 24 16
 25 17
 26 18
 27 19
 28 20
 29 21
 30 22
 31 23
 32 24
 33 25
 34 26
 35 27
 36 28
 37 29
 38 30
 39 //主线程中
 40 NSLock *theLock = [[NSLock alloc] init];
 41 TestObj *obj = [[TestObj alloc] init];
 42
 43 //线程1
 44 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
 45
 46     static void(^TestMethod)(int);
 47     TestMethod = ^(int value)
 48     {
 49         [theLock lock];
 50         if (value > 0)
 51         {
 52             [obj method1];
 53             sleep(5);
 54             TestMethod(value-1);
 55         }
 56         [theLock unlock];
 57     };
 58
 59     TestMethod(5);
 60 });
 61
 62 //线程2
 63 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
 64     sleep(1);
 65     [theLock lock];
 66     [obj method2];
 67     [theLock unlock];
 68 });
 69 以上的代码中,就是一种典型的死锁情况,因为在线程1中的递归block中,锁会被多次的lock,所以自己也被阻塞了,由于以上的代码非常的简短,所以很容易能识别死锁,但在较为复杂的代码中,就不那么容易发现了,那么如何在递归或循环中正确的使用锁呢?此处的theLock如果换用NSRecursiveLock对象,问题便得到解决了,NSRecursiveLock类定义的锁可以在同一线程多次lock,而不会造成死锁。递归锁会跟踪它被多少次lock。每次成功的lock都必须平衡调用unlock操作。只有所有的锁住和解锁操作都平衡的时候,锁才真正被释放给其他线程获得。
 70
 71 2.NSConditionLock条件锁
 72
 73 当我们在使用多线程的时候,有时一把只会lock和unlock的锁未必就能完全满足我们的使用。因为普通的锁只能关心锁与不锁,而不在乎用什么钥匙才能开锁,而我们在处理资源共享的时候,多数情况是只有满足一定条件的情况下才能打开这把锁:
 74
 75 1
 76 2
 77 3
 78 4
 79 5
 80 6
 81 7
 82 8
 83 9
 84 10
 85 11
 86 12
 87 13
 88 14
 89 15
 90 16
 91 17
 92 18
 93 19
 94 20
 95 //主线程中
 96 NSConditionLock *theLock = [[NSConditionLock alloc] init];
 97
 98 //线程1
 99 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
100     for (int i=0;i<=2;i++)
101     {
102         [theLock lock];
103         NSLog(@"thread1:%d",i);
104         sleep(2);
105         [theLock unlockWithCondition:i];
106     }
107 });
108
109 //线程2
110 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
111     [theLock lockWhenCondition:2];
112     NSLog(@"thread2");
113     [theLock unlock];
114 });
115 在线程1中的加锁使用了lock,所以是不需要条件的,所以顺利的就锁住了,但在unlock的使用了一个整型的条件,它可以开启其它线程中正在等待这把钥匙的临界地,而线程2则需要一把被标识为2的钥匙,所以当线程1循环到最后一次的时候,才最终打开了线程2中的阻塞。但即便如此,NSConditionLock也跟其它的锁一样,是需要lock与unlock对应的,只是lock,lockWhenCondition:与unlock,unlockWithCondition:是可以随意组合的,当然这是与你的需求相关的。
116
117 3.NSDistributedLock分布式锁
118
119 以上所有的锁都是在解决多线程之间的冲突,但如果遇上多个进程或多个程序之间需要构建互斥的情景该怎么办呢?这个时候我们就需要使用到NSDistributedLock了,从它的类名就知道这是一个分布式的Lock,NSDistributedLock的实现是通过文件系统的,所以使用它才可以有效的实现不同进程之间的互斥,但NSDistributedLock并非继承于NSLock,它没有lock方法,它只实现了tryLock,unlock,breakLock,所以如果需要lock的话,你就必须自己实现一个tryLock的轮询,下面通过代码简单的演示一下吧:
120
121 程序A:
122
123 1
124 2
125 3
126 4
127 5
128 6
129 7
130 8
131 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
132     lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/earning__"];
133     [lock breakLock];
134     [lock tryLock];
135     sleep(10);
136     [lock unlock];
137     NSLog(@"appA: OK");
138 });
139 程序B:
140
141 1
142 2
143 3
144 4
145 5
146 6
147 7
148 8
149 9
150 10
151 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
152         lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/earning__"];
153
154         while (![lock tryLock]) {
155             NSLog(@"appB: waiting");
156             sleep(1);
157         }
158         [lock unlock];
159         NSLog(@"appB: OK");
160     });
161 先运行程序A,然后立即运行程序B,根据打印你可以清楚的发现,当程序A刚运行的时候,程序B一直处于等待中,当大概10秒过后,程序B便打印出了appB:OK的输出,以上便实现了两上不同程序之间的互斥。/Users/mac/Desktop/earning__是一个文件或文件夹的地址,如果该文件或文件夹不存在,那么在tryLock返回YES时,会自动创建该文件/文件夹。在结束的时候该文件/文件夹会被清除,所以在选择的该路径的时候,应该选择一个不存在的路径,以防止误删了文件。
时间: 2024-12-28 15:57:21

Objective-C中不同方式实现锁(二)-11-多线程的相关文章

Objective-C中不同方式实现锁(一)-12-多线程

Objective-C中不同方式实现锁(一) 为什么需要使用锁,当然熟悉多线程的你,自然不会对它觉得陌生. 那你在代码中是否很好的使用了锁的机制呢?你又知道几种实现锁的方法呢? 今天一起来探讨一下Objective-C中几种不同方式实现的锁,在这之前我们先构建一个测试用的类,假想它是我们的一个共享资源,method1与method2是互斥的,代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 @implementation TestObj - (void)method1 {

oc中不同方式实现锁

今天一起来探讨一下Objective-C中几种不同方式实现的锁,在这之前我们先构建一个测试用的类,假想它是我们的一个共享资源,method1与method2是互斥的,代码如下: 12345678910111213 @implementation TestObj - (void)method1{    NSLog(@"%@",NSStringFromSelector(_cmd));} - (void)method2{    NSLog(@"%@",NSStringFr

web开发中的两把锁之数据库锁:(高并发--乐观锁、悲观锁)

这篇文章讲了 1.同步异步概念(消去很多疑惑),同步就是一件事一件事的做:sychronized就是保证线程一个一个的执行. 2.我们需要明白,锁机制有两个层面,一种是代码层次上的,如Java中的同步锁,典型的就是同步关键字synchronized ( 线    程级别的).另一个就是数据库层次上的,比较典型的就是悲观锁和乐观锁. 3.常见并发同步案例分析   附原文链接 http://www.cnblogs.com/xiohao/p/4385508.html 对于我们开发的网站,如果网站的访问

支付宝防并发方案之&quot;一锁二判三更新&quot;

每年支付宝在双11和双12的活动中,都展示了绝佳的技术能力.这个能力不但体现在处理高TPS量的访问,更体现在几乎不会出错,不会出现重复支付的情况,那这个是怎么做到的呢? 诚然,为了实现在高并发下仍不会出错的技术目标,支付宝下了很多功夫,比如幂等性的处理,分布式事务的使用等等,但是个人觉得其中最关键的一点就是"一锁二判三更新"这句看似毫不起眼的口诀. 何为"一锁二判三更新"? 简单来说就是当任何一个并发请求过来的时候 1. 我们先锁定关联单据 2. 然后判断关联单据状

[数据库事务与锁]详解五: MySQL中的行级锁,表级锁,页级锁

注明: 本文转载自http://www.hollischuang.com/archives/914 在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足. 在数据库的锁机制中介绍过,在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎).表级锁(MYISAM引擎)和页级锁(BDB引擎 ). 行级锁 行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁.行级锁能大大减少数据库操作的冲突.其加锁粒度最小,但加锁的

MySQL中select * for update锁表的范围

MySQL中select * for update锁表的问题 由于InnoDB预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL才会执行Row lock (只锁住被选取的资料例) ,否则MySQL将会执行Table Lock (将整个资料表单给锁住). 举个例子: 假设有个表单products ,里面有id跟name二个栏位,id是主键. 例1: (明确指定主键,并且有此笔资料,row lock) SELECT * FROM products WHERE id='3' F

DB2中三个有关锁变量DB2_EVALUNCOMMITTED,DB2_SKIPDELETED和DB2_SKIPINSERTED的使用

本文主要解释下DB2中三个有关锁变量DB2_EVALUNCOMMITTED,DB2_SKIPDELETED和DB2_SKIPINSERTED的使用 实验环境: DB2 v9.7.0.6 AIX 6.1.0.0 採用默认的隔离级别CS STUDENT表的DDL与初始内容 CREATE TABLE "E97Q6C  "."STUDENT"  ( "AGE" INTEGER , "NAME" CHAR(8) ) IN "U

objective C中的字符串(三)

holydancer原创,如需转载,请在显要位置注明: 转自holydancer的CSDN专栏,原文地址:http://blog.csdn.net/holydancer/article/details/7343561 objective C中的字符串操作 在OC中创建字符串时,一般不使用C的方法,因为C将字符串作为字符数组,所以在操作时会有很多不方便的地方,在Cocoa中NSString集成的一些方法,可以很方便的操作字符串,下面举几个例子: 1.创建: 直接利用等号赋值 NSString *

【转】WPF中的Binding技巧(二)

WPF中的Binding技巧(二)   接上篇, 我们来看一看Elementname,Source,RelativeSource 三种绑定的方式 1.ElementName顾名思义就是根据Ui元素的Name来进行绑定: 例子: <Window x:Name="MainWindow"> <Grid>               <Button Background="{Binding ElementName=MainWindow, Path=Bac