概述

在多线程编程中往往会遇到多个线程同时访问共享的资源,这种情况我们需要通过同步线程来避免。也就是给线程加锁。

因为Objective-CC语言的超集。,严格的来说是真超集。所以C语言当中的pthread互斥锁在Objective-C中也可以使用,但是Objective-C中定义了本身自己的锁对象和锁协议,所以本篇介绍Objective-C中的锁。

NSLock

NSLocking协议

@protocol NSLocking
- (void)lock;
- (void)unlock;
@end

后面介绍的几种锁类型NSLock,NSConditionLock,NSRecursiveLock,都实现了该协议可以统一用lockunlock进行加锁与解锁。


NSLock使用

    NSLock *lock = [[NSLock alloc] init];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[lock lock]; //获取锁
NSLog(@"lock success");
sleep(5);
NSLog(@"sleep end");
[lock unlock]; //放弃之前获取的锁
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[lock lock]; //获取锁,如果获取不到阻塞当前线程直到获取到锁
NSLog(@"remove lock");
[lock unlock]; //放弃获取到的锁
});

输出结果

 lock success
sleep end
remove lock

NSLock对象发送lock消息时先检查能不能获取到这个锁,如果此时在其他线程中正在使用这个锁那么阻塞当前线程一直等待其他线程使用完这个锁unlock放弃这个锁后,才可以在自己当前的线程重新获取到,线程恢复。如果一直获取不到这个锁那么线程将一直阻塞,所以lockunlock这两个方法一定要成对出现。当然还有不阻塞调用锁的线程方法tryLocklockBeforeDate:


tryLock

tryLock尝试获取锁,如果获取不到返回NO,反之YES,不会阻塞当前调用它的线程

    NSLock *lock = [[NSLock alloc] init];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[lock lock]; //获取锁
NSLog(@"lock success");
sleep(5);
NSLog(@"sleep end");
[lock unlock]; //放弃之前获取的锁
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
if ([lock tryLock]) //尝试获取锁,如果获取不到返回NO,不会阻塞该线程
{
NSLog(@"remove lock");
[lock unlock];
}
else{
NSLog(@"obtain failure");
}
});

输出结果

lock success
obtain failure
sleep end

获取失败是因为当前锁正在其他线程中使用。如果当前锁没有使用那么会返回YES

lockBeforeDate

lockBeforeDate阻塞调用它的线程,如果给定时间内不能够获取锁那么放弃获取并恢复线程。

    NSLock *lock = [[NSLock alloc] init];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[lock lock]; //获取锁
NSLog(@"lock success");
sleep(5);
NSLog(@"sleep end");
[lock unlock]; //放弃之前获取的锁
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSDate *date = [[NSDate alloc] initWithTimeIntervalSinceNow:3];
if ([lock lockBeforeDate:date]) //尝试在未来的3s内获取锁,并阻塞该线程,如果3s内获取不到恢复线程
{
NSLog(@"remove lock");
[lock unlock];
}
else{
NSLog(@"obtain failure");
}
});

输出结果

 lock success
obtain failure
sleep end

如果3s内获取不到则返回NO,否则返回YES

@synchronized

synchronized对一个对象提供锁定和解锁机制。synchronized会阻塞调用它的线程

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
@synchronized (self) {
[self logging:@"lock success"];
sleep(5);
[self logging:@"sleep end"];
}
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
@synchronized (self) //等到上面线程执行完后才回执行下面的代码,此时会阻塞当前线程
{
[self logging:@"remove lock"];
}
});

输出结果

 lock success
sleep end
remove lock

上面对自身对象进行加锁直到上面第一个GCD全部执行结束才会执行下面加锁的代码。

注意

Objective-C类自身也是对象所以可以对这些类对象使用synchronized,此时是对整个对象类型进行线程同步。例如:

    @synchronized ([self class]) {
}

NSConditionLock

NSConditionLock条件锁,获取锁时必须与之前设置解锁的条件一样时才可以获取到,否则当前线程一直阻塞,直到条件一致时线程才可以恢复。

最典型的例子就是生产者-消费者场景,当数据为空时生产者生产数据此时消费者不能够获取数据,生产者生产数据后,消费者处理数据,直到消费者处理所有数据后,数据又为空,此时生产者继续生产数据。示例代码如下:

    enum {NO_DATA_IN_QUEUE = 0,HAS_DATA_IN_QUEUE};
NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:NO_DATA_IN_QUEUE]; dispatch_async(dispatch_get_global_queue(0, 0), ^{
while (YES) {
[conditionLock lockWhenCondition:NO_DATA_IN_QUEUE];
NSLog(@"insert data");
sleep(3);
NSLog(@"intset success");
[conditionLock unlockWithCondition:HAS_DATA_IN_QUEUE];
}
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
while (YES) {
[conditionLock lockWhenCondition:HAS_DATA_IN_QUEUE];
NSLog(@"delete data");
sleep(3);
NSLog(@"delete success");
[conditionLock unlockWithCondition:NO_DATA_IN_QUEUE];
}
});

输出结果:

 insert data
intset success
delete data
delete success
insert data
intset success
delete data
delete success
...

NSRecursiveLock

NSRecursiveLock递归锁,当我们对一个递归函数同步线程时会在同一个线程多次获取锁,导致线程死锁,NSRecursiveLock可以在同一个线程多次获取锁不会死锁。

NSRecursiveLock *recursiveLock = [[NSRecursiveLock alloc] init];
dispatch_async(dispatch_get_global_queue(0, 0), ^{ static void (^recursive)(int count);
recursive = ^(int count){
[recursiveLock lock];
if (count>0) {
NSLog(@"success lock");
sleep(3);
recursive(--count);
}
[recursiveLock unlock];
};
recursive(3); });

上面这种情况如果使用NSLock在没有解锁时继续获取锁,就会造成死锁导致线程一致堵塞。

NSDistributedLock

NSDistributedLock是Mac多线程开发中的互斥锁解决方案,在此不多做介绍。

Objective-C中的同步线程的锁的更多相关文章

  1. c#中多线程同步Lock(锁)的研究以及跨线程UI的操作

    本文只针对C#中,多线程同步所用到的锁(lock)作为研究对象.由于想更直观的显示结果,所以,在做demo的时候,就把多线程通过事件操作UI的代码也写了出来,留作备忘和分享吧. 其实多线程的同步,使用 ...

  2. c#中多线程同步Lock(锁)的研究以及跨线程UI的操作 (转)

    https://www.cnblogs.com/tommyheng/p/4104552.html 本文只针对C#中,多线程同步所用到的锁(lock)作为研究对象.由于想更直观的显示结果,所以,在做de ...

  3. JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制

    JAVA之旅(十四)--静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是clas ...

  4. JAVA语言规范-线程和锁章节之同步、等待和通知

    JAVA语言规范:线程和锁 1 同步 java编程语言提供了线程间通信的多种机制.这些方法中最基本的是同步化,此方法是使用监视器实现的.JAVA中每个对象与一个监视器相关联,一个线程可以加锁和解锁监视 ...

  5. C++11 中的线程、锁和条件变量

    转自:http://blog.jobbole.com/44409/ 线程 类std::thread代表一个可执行线程,使用时必须包含头文件<thread>.std::thread可以和普通 ...

  6. JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this

    JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程 ...

  7. Java线程中的同步

    1.对象与锁 每一个Object类及其子类的实例都拥有一个锁.其中,标量类型int,float等不是对象类型,但是标量类型可以通过其包装类来作为锁.单独的成员变量是不能被标明为同步的.锁只能用在使用了 ...

  8. ReentrantLock+线程池+同步+线程锁

    1.并发编程三要素? 1)原子性 原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行. 2)可见性 可见性指多个线程操作一个共享变量时,其中一个线程对变量 ...

  9. jvm高级特性(6)(线程的种类,调度,状态,安全程度,实现安全的方法,同步种类,锁优化,锁种类)

    JVM高级特性与实践(十三):线程实现 与 Java线程调度 JVM高级特性与实践(十四):线程安全 与 锁优化 一. 线程的实现 线程其实是比进程更轻量级的调度执行单位. 线程的引入,可以把一个检查 ...

随机推荐

  1. 51nod-1503 猪和回文 - 二维矩阵上的dp

    题目链接 一只猪走进了一个森林.很凑巧的是,这个森林的形状是长方形的,有n行,m列组成.我们把这个长方形的行从上到下标记为1到n,列从左到右标记为1到m.处于第r行第c列的格子用(r,c)表示. 刚开 ...

  2. 74HC165应用

    管脚定义与内部逻辑图 注1:其中控制管脚有3个:SH/LD-QH-CLK,CLK INH硬件接VSS,SER和QH'悬空 原理:先拉低SH/LD,A-H置入芯片内部寄存器中,然后拉高SH/LD,锁住A ...

  3. Site Isolation Design Document

    This design document covers technical information about how Site Isolation is built.  For a general ...

  4. NOIp模拟赛三十一

    持续降智 分数:100+0+0=100 C题subtask是假的,根本没有部分分中的情况...还我20分QAQ A:[BZOJ4444]国旗计划 B:[agc006f]blackout C:[arc0 ...

  5. Unity shader UI的3D效果

    原创,转载请标明出处 1.效果 scene视图中的效果: game视图中效果: 2.核心思想:改变UI的顶点坐标 3.好处:可以用正交相机来实现3D效果. 4.Shader 实现 // Unity b ...

  6. hadoop-04-mysql安装

    hadoop-04-mysql安装 su root 1,rpm -qa|grep mysql 2, rpm -e --nodeps `rpm -qa|grep mysql` 3,rpm -ivh co ...

  7. hdu 5277 YJC counts stars

    hdu 5277 YJC counts stars 题意: 给出一个平面图,n个点,m条边,直线边与直线边之间不相交,求最大团的数目. 限制: 1 <= n <= 1000 思路: 因为平 ...

  8. jsp布局中关于&lt;iframe&gt;标签的使用

    iframe 元素会创建包括另外一个文档的内联框架(即行内框架). 注意:在 HTML 4.1 Strict DTD 和 XHTML 1.0 Strict DTD 中,不支持 iframe 元素. & ...

  9. less06 引入(importing)

    main.less @wp:960px; .colorsss{ color: darkgreen; } index.css .color{ color: #ff6600; } style.less / ...

  10. hdoj--2138--How many prime numbers(暴力模拟)

    How many prime numbers Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/O ...