博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS 互斥锁简单使用
阅读量:6214 次
发布时间:2019-06-21

本文共 6558 字,大约阅读时间需要 21 分钟。

hot3.png

的作用是创建一个互斥锁,保证此时没有其它线程对self对象进行修改。这个是objective-c的一个锁定令牌,防止self对象在同一时间内被其它线程访问,起到线程的保护作用.

-(void)viewDidLoad{    self.totalCount = 100;        self.lock = [[NSLock alloc] init];        self.threadA = [[NSThread alloc] initWithTarget:self selector:@selector(sale) object:nil];    self.threadA.name = @"售票员A";        self.threadB = [[NSThread alloc] initWithTarget:self selector:@selector(sale) object:nil];    self.threadB.name = @"售票员B";        self.threadC = [[NSThread alloc] initWithTarget:self selector:@selector(sale) object:nil];    self.threadC.name = @"售票员C";}-(void)sale{    while (1) {                //使用synchronized保证同一时间只能有一个出票的行为;        @synchronized(self){            NSInteger count = self.totalCount;                        for(NSInteger i = 0; i < 100000; i++){                            }                        if(count > 0){                self.totalCount = count - 1;                NSLog(@"%@卖了一张票, 还剩%zd张票",[NSThread currentThread].name, self.totalCount);            }else{                NSLog(@"票卖完了");                break;            }        }      };    }}-(void)touchesBegan:(NSSet
*)touches withEvent:(UIEvent *)event{ [self.threadA start]; [self.threadB start]; [self.threadC start];}

NSLock

lock:加锁unlock:解锁tryLock:尝试加锁,返回值是布尔类型;返回YES,加锁成功;返回NO,加锁失败,立即退出,不会阻塞线程;
-(void)sale{    while (1) {                //尝试加锁,返回YES,执行代码,并解锁;返回NO,不执行操作;        //也可以直接执行 [self.lock lock]加锁        if([self.lock tryLock]){            NSInteger count = self.totalCount;                        for(NSInteger i = 0; i < 100000; i++){                            }                        if(count > 0){                self.totalCount = count - 1;                NSLog(@"%@卖了一张票, 还剩%zd张票",[NSThread currentThread].name, self.totalCount);            }else{                NSLog(@"票卖完了");                break;            }                        [self.lock unlock];        }    }}

NSConditionLock

NSConditionLock和NSLock类似,参数多了一个condition; 加锁时 lockWhenCondition、tryLockWhenCondition,只有 condition 参数与初始化时候的 condition 相等,lock 才能正确进行加锁操作; 解锁 unlockWithCondition,并不是condition符合条件才解锁,而是解锁时修改condition的值

-(void)touchesBegan:(NSSet
*)touches withEvent:(UIEvent *)event{ dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self.conditionLock lockWhenCondition:0]; NSLog(@"线程1"); sleep(1); [self.conditionLock unlock]; }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ // [self.conditionLock lockWhenCondition:1]; [self.conditionLock tryLockWhenCondition:1]; NSLog(@"线程2"); sleep(1); [self.conditionLock unlockWithCondition:2]; NSLog(@"线程2解锁成功"); }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ // [self.conditionLock lockWhenCondition:2]; [self.conditionLock tryLockWhenCondition:2]; NSLog(@"线程3"); sleep(1); [self.conditionLock unlockWithCondition:0]; NSLog(@"线程3解锁成功"); });}执行结果:2017-10-11 11:16:58.142126+0800 test[4652:1892785] 线程22017-10-11 11:16:59.147742+0800 test[4652:1892785] 线程2解锁成功2017-10-11 11:16:59.147951+0800 test[4652:1892784] 线程32017-10-11 11:17:00.151930+0800 test[4652:1892784] 线程3解锁成功2017-10-11 11:17:00.152230+0800 test[4652:1892783] 线程1

NSRecursiveLock

NSRecursiveLock是递归锁,他和 NSLock 的区别在于,NSRecursiveLock 可以在一个线程中重复加锁(反正单线程内任务是按顺序执行的,不会出现资源竞争问题),NSRecursiveLock 会记录上锁和解锁的次数,当二者平衡的时候,才会释放锁,其它线程才可以上锁成功。

NSRecursiveLock *lock = [[NSRecursiveLock alloc] init];dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    static void (^RecursiveBlock)(int);    RecursiveBlock = ^(int value) {        [lock lock];        if (value > 0) {            NSLog(@"value:%d", value);            RecursiveBlock(value - 1);        }        [lock unlock];    };    RecursiveBlock(2);});

2017-10-11 11:31:08.792344+0800 test[4668:1898431] value:2 2017-10-11 11:31:08.792516+0800 test[4668:1898431] value:1

如上面的示例,如果用 NSLock 的话,lock 先锁上了,但未执行解锁的时候,就会进入递归的下一层,而再次请求上锁,阻塞了该线程,线程被阻塞了,自然后面的解锁代码不会执行,而形成了死锁。而 NSRecursiveLock 递归锁就是为了解决这个问题。

NSCondition

NSCondition 的对象实际上作为一个锁和一个线程检查器,锁上之后其它线程也能上锁,而之后可以根据条件决定是否继续运行线程,即线程是否要进入 waiting 状态,经测试,NSCondition 并不会像上文的那些锁一样,先轮询,而是直接进入 waiting 状态,当其它线程中的该锁执行 signal 或者 broadcast 方法时,线程被唤醒,继续运行之后的方法。 signal 只是一个信号量,只能唤醒一个等待的线程,想唤醒多个就得多次调用,而 broadcast 可以唤醒所有在等待的线程。如果没有等待的线程,这两个方法都没有作用。

dispatch_async(dispatch_get_global_queue(0, 0), ^{               [self.condition lock];                if(self.array.count == 0){            [self.condition wait];        }                [self.array removeAllObjects];        NSLog(@"remove all objects");        [self.condition unlock];    });        dispatch_async(dispatch_get_global_queue(0, 0), ^{               sleep(1);        [self.condition lock];        [self.array addObject:@1];        NSLog(@"add object");        [self.condition signal];        [self.condition unlock];    });

dispatch_semaphore

dispatchsemaphorecreate(long value);

dispatchsemaphorewait(dispatchsemaphoret dsema, dispatchtimet timeout);

dispatchsemaphoresignal(dispatchsemaphoret dsema); dispatch_semaphore 是 GCD 用来同步的一种方式,与他相关的只有三个函数,一个是创建信号量,一个是等待信号,一个是发送信号。

dispatch_semaphore_t signal = dispatch_semaphore_create(1);dispatch_time_t overTime = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC);dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    dispatch_semaphore_wait(signal, overTime);    sleep(2);    NSLog(@"线程1");    dispatch_semaphore_signal(signal);});dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    sleep(1);    dispatch_semaphore_wait(signal, overTime);    NSLog(@"线程2");    dispatch_semaphore_signal(signal);});

dispatchsemaphore 和 NSCondition 类似,都是一种基于信号的同步方式,但 NSCondition 信号只能发送,不能保存(如果没有线程在等待,则发送的信号会失效)。而 dispatchsemaphore 能保存发送的信号。dispatchsemaphore 的核心是 dispatchsemaphore_t 类型的信号量。

dispatchsemaphorecreate(1) 方法可以创建一个 dispatchsemaphoret 类型的信号量,设定信号量的初始值为 1。注意,这里的传入的参数必须大于或等于 0,否则 dispatchsemaphorecreate 会返回 NULL。

dispatchsemaphorewait(signal, overTime); 方法会判断 signal 的信号值是否大于 0。大于 0 不会阻塞线程,消耗掉一个信号,执行后续任务。如果信号值为 0,该线程会和 NSCondition 一样直接进入 waiting 状态,等待其他线程发送信号唤醒线程去执行后续任务,或者当 overTime 时限到了,也会执行后续任务。

dispatchsemaphoresignal(signal); 发送信号,如果没有等待的线程接受信号,则使 signal 信号值加一(做到对信号的保存)。

从上面的实例代码可以看到,一个 dispatchsemaphorewait(signal, overTime); 方法会去对应一个 dispatchsemaphoresignal(signal); 看起来像 NSLock 的 lock 和 unlock,其实可以这样理解,区别只在于有信号量这个参数,lock unlock 只能同一时间,一个线程访问被保护的临界区,而如果 dispatch_semaphore 的信号量初始值为 x ,则可以有 x 个线程同时访问被保护的临界区。

转载于:https://my.oschina.net/mexiaobai1315/blog/1549115

你可能感兴趣的文章
《代码之殇》(原书第2版)——第2章 过程改进,没有灵丹妙药 2004年10月1日...
查看>>
写给运营商的三个锦囊
查看>>
其他类安防生产型上市企业2015年经营情况
查看>>
上汽集团结盟传感器制造商Savari
查看>>
喜欢吗?微软公布新版Win10开始菜单:致敬Win8
查看>>
华芯投资40亿现金收购美芯片测试设备厂商Xcerra
查看>>
程序员当选全球轮值总裁 WiFi万能钥匙誓做中国“最科技”
查看>>
光伏电站美的三层境界
查看>>
Spring MVC学习笔记之Hello World
查看>>
Google的排名优化需要注意哪些方面的细节?
查看>>
《Android的设计与实现:卷I》——第2章 2.6JNI异常处理
查看>>
《系统分析与设计方法及实践》一2.4 软件过程模型
查看>>
HiTSDB 上云功能性列表
查看>>
排名前三:微软2015年全球云系统管理软件业务增势强劲
查看>>
网络运营商的数据中心转型
查看>>
从致远软件到致远互联,见证to B产业的时代交接
查看>>
Google企业网盘Team Drives面向商业客户开放私测
查看>>
拉格朗日乘数法
查看>>
面对网络攻击,我们为何如此脆弱?
查看>>
智慧城市运营商中创智慧拟挂牌新三板
查看>>