准备工作
- swift-corelibs-foundation 源码
一、锁的分类
互斥锁
互斥锁有互斥和同步两条特性,互斥性:当多条线程同时处理一个任务时,一条线程在处理任务,其他线程安全教育日都不能再进行处理,只有该任务结束运行后才可以运行。同步源码性:首先要满足互斥性,还要有执行的顺序。常用的有:
- @sy安全教育日nchronized
- NSLock
- pthread_mutex
自旋锁
自旋锁相当于互斥锁+忙等,当其检测到资源不可用时,会保持一种忙初始化等的状态,直到获取该资源。它的优势在于避免了上下文的切换,非常适合于堵塞线程池的七个参数时间很短的场合。缺点则是变量泵在忙等的状初始化磁盘态下会不停的检测状态,会占用cpu资源。常用的有:
OSSpinLockatomic
条件锁
通过一些条件来控制资源的访问,当然条件是会发生变化的。常用的有:
NSConditionNSConditionLock
信号量
是一种高级的同步机制。互斥锁可以认为是信号量取值0/1时的特例,可以线程池的七个参数实现更加复杂的同步。常用的有:
dispatch_semaphore
递归锁初始化sdk什么意思
它允许同一线程多次加锁,而不会造成死锁。递归锁是特殊的互斥锁,主要是用在循环或递归操作中。常用的有:
pthread_mutex(recursive)NSRecursiveLock
读写锁安全教育手抄报
是并发控制的一种同步机制,也称“共享-互斥锁”,也是一种特殊的自旋锁。它把对资源的访问者分为读者和写者,它允许同时有多个变量名读者访问资源,但是只允许有一个写者来访问资源源码。常用的有:
pthread(rwlock)dispatch_barrier_async / dispatch_barrier_sync
二、NSLo变量类型有哪些ck 和 NSRecur源码精灵永久兑换码siveLock 的分析
先看下面的示例代码,外层是for循环,内层是block的递归调用:
- (void)ssl_testRecursive {
for (int i = 0; i < 10; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
static void (^testMethod)(int);
testMethod = ^(int value){
if (value > 0) {
NSLog(@"current value= %d",value);
testMethod(value - 1);
}
};
testMethod(10);
});
}
}
查看执行结果:
- 可以看到
value值是乱序打印的,如果我们想要顺序打印,就要给代码加锁,那么该怎么加锁呢。
NSLock 示例
在testMethod(10);的执行前后加上NSLock锁:
- 没有问题,可以顺序打印。
有的时候,我们喜欢把加锁和业务代码写在一起,也就是初始化电脑在testMethod的block中加锁:
- 只打印了一个
10,为什么呢,因为这是个递归函数,会递归加锁,而NSLock是非递归锁,所以无法正常执行。
NSRecursiv安全教育日eLock 示例
N初始化失败是怎么解决SRecursiveLock是递归锁,我们安全教育手抄报把N变量类型有哪些SLock换成NSRecursiveLock源码1688,运行程序:初始化英文
- 程初始化英文序从
10到1只顺序打印了1次,这又是为什么呢,因为NSRecursiveLock只是递归锁,可以解决递归性但是解决不了多线程性,那么既要满足递归性又要满足多线程性就需要用到我们 上一篇 分析的@synchronized。
@synchronized 示例
使用@synchronized,程序正常打印:
三、NSCondition 的分析
简介
SCondition是一个条件锁,在日常开发中使用较少,与信号量有点相似:线程需要满足条件才会往下走初始化电脑时出现问题,否则会堵塞变量的定义等待,直到条件满足,是经典的生产消费者模型。
NSCondition的对象实际上作为一个锁和一个线程线程池面试题检查器:
-
锁主要为了变量类型有哪些当检测条件时保护数据源,执行条件引发的任务。 -
线程检查器主要是根据条件决定是否继续运行线程,即线程安全线程是否被阻塞。
相关函数
//一般用于多线程同时访问、修改同一个数据源,保证在同一时间内数据源只被访问、修改一次,其他线程的命令需要在lock 外等待,只到 unlock ,才可访问
[condition lock];
//与lock 同时使用
[condition unlock];
//让当前线程处于等待状态
[condition wait];
//CPU发信号告诉线程不用在等待,可以继续执行
[condition signal];
生产消费者模安全工程师型 示例
- (void)viewDidLoad {
[super viewDidLoad];
[self ssl_testConditon];
}
- (void)ssl_testConditon {
_testCondition = [[NSCondition alloc] init];
//创建生产-消费者
for (int i = 0; i < 50; i++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self ssl_producer];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self ssl_consumer];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self ssl_consumer];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self ssl_producer];
});
}
}
- (void)ssl_producer {
[_testCondition lock]; // 操作的多线程影响
self.ticketCount = self.ticketCount + 1;
NSLog(@"生产一个 现有 count %zd",self.ticketCount);
[_testCondition signal]; // 信号
[_testCondition unlock];
}
- (void)ssl_consumer {
[_testCondition lock]; // 操作的多线程影响
if (self.ticketCount == 0) {
NSLog(@"等待 count %zd",self.ticketCount);
[_testCondition wait];
}
//注意消费行为,要在等待条件判断之后
self.ticketCount -= 1;
NSLog(@"消费一个 还剩 count %zd ",self.ticketCount);
[_testCondition unlock];
}
执行结果:
生产一个 现有 count 1
消费一个 还剩 count 0
等待 count 0
等待 count 0
生产一个 现有 count 1
消费一个 还剩 count 0
生产一个 现有 count 1
消费一个 还剩 count 0
等待 count 0
生产一个 现有 count 1
...
- 生产者生产,消费者消线程数越多越好吗费,
消费者消费生产者生产的,如果不能生产就不能消费。 - 生产者和消费者,本身要是初始化失败是怎么解决安全的要进行加锁,它们之间又有联系,需要信线程安全号的控制,消费为
0时要进行等待,生产有了以后不能让消费一直等待,要发送信号消费者就可以结束等待继续执行。
四、foundation 源码关于锁的封装
我们看下NSLock的定义:
-
lock和unlock是NSLocking的协议方法,是一个锁的协议,很多锁都有这两个方法,接下来结合swift-corelibs-foundation源码分析NSLock到底是怎么实现的。
NSLock 源码分析
查看NSLock安全工程师源码:
- 可以看到
NSLock源码中确实是实现了NSLocking协议,线程数是什么初始化时,本质上是对pthread_mutex源码之家进行的封装,调用的都是变量pthread_mutex的函数。
查看lock、unlock的实变量现:
- 可以看到
lock和unlock也是初始化是什么意思对pthread_mutex进行的封装。
NSRecursiveLock 源码分析
查看NSRecursiveLock源码:
- 可以看到
NSRecursiveLock也实现了NSLocking协议,初始化也是用pthread_mutex进行的封装,不同之处在源码编辑器下载于NSRecursiveLock中安全模式有设置PTHREAD_MUTEX_RECURSIVE这个type,这里就决定了它是个递归锁。
N初始化英文SRecursiveLock的lock、unlock的实现和NSLock基本是一样的,都是对pthread_mutex的封装:
NSCondition 源码分析
查看NSConditi初始化on源码:
-
NSConditi安全on也实现了NSLoc变量king协议,初始化也是用pthread_mu变量之间的关系tex进行的封装,区别就在于封装了cond的相关操作,使它拥有了wait、signal等功能。
lock和unlock也是对pthread_mutex的封装:
五、NSConditionLock 分析
NSConditionLock 示例
看下面的示例代码及执行结果:
- (void)ssl_testConditonLock{
NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:2];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[conditionLock lockWhenCondition:1];
NSLog(@"线程 1");
[conditionLock unlockWithCondition:0];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
[conditionLock lockWhenCondition:2];
sleep(0.1);
NSLog(@"线程 2");
[conditionLock unlockWithCondition:1];
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[conditionLock lock];
NSLog(@"线程 3");
[conditionLock unlock];
});
//
}
执行结果:
线程 3
线程 2
线程 1
-
线程 2一定在线程 1之前先执行,因为我们初始化condi线程池面试题tionLock时指定的condition等于2,所以lockWhenCondition:2可以正常执行,unlockWithCondition:1安全教育平台登录以后lockWhenCond安全教育平台登录ition:1才能执行。 -
线程 3中只是普通的lock所以是可以正常执行,线程 2和线程 3本来是乱序的,但我们在线程 2加了sleep(0.1)延安全生产法迟操作,所以线程 3先执行。
NSConditionLock 源码分析
初始化源码分析
打开源码,查看NSConditionLock的初始化:
- 通过
NSCo源码交易平台nd变量类型有哪些ition()初始线程撕裂者化了成员变量_cond。 - 初始化
_value成员变量为0。
lockWhen变量名Condition: 源码分析
查看lockWhenCondition:源码:
继续进入whenCondition:before::
- 当
_value != condition时进行源码编程器while死循环,循环中安全教育平台判断等待是否超时,如果超时了返回fa源码lse,如果等到_value == condition向下执行返回true,任务正常执行。
unloc源码时代kWithCondition: 源码分析
unlockWithCondition::
- 更新
_变量类型有哪些value值为传进来的condition。 -
_cond.broadcast()进行广播通知,通知等待中的任务_value值的改变。
六、读写锁
读写锁 概念
-
读写锁实际是一种特殊的互斥锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。这种锁相对于自旋锁而言,能提高并发性,因为在多处理器系统中,它允许同时有多个读者来访问共享资源,最大可初始化电脑的后果能的读者数为实际的逻辑CPU数。写者是初始化电脑排他性的,一个读写锁同时只能有一个写者或多个读者(与CPU数相关),但不能同时既有读者又有写者。在读写锁保持期间也是抢占失效的。 - 如果读写锁当前没有读者,也没有写者,那么写者初始化失败是怎么解决可以立刻获得读写锁,否则它必须自旋在那里,直到没有任何写者或读者。如果安全生产法读写锁没有写变量泵者,那么读者可以立即获得该读写锁,否则读者必须自旋在那里,直到写者释放该读写锁。
- 一次
只有一个线程可以占有安全教育日写模式的读写锁, 但是可变量以有多个线程同时占有读模式的读写锁,正是因为这初始化是什么意思个特性,当读写锁是写加锁状态时, 在这个锁被解锁之前, 所有试图对这个锁加锁的线程都会被阻塞。 - 当读写锁在
读加变量值锁状态时, 所有试图以读模式对它进行加锁的线程都可以得到访问权, 但是如果线程希望以写模式对此锁进行源码网站加锁, 它必须直到所有的线程释放锁。 - 通常,当读写锁处于
读模式锁住状态时, 如果有另外线程试图以写模式加锁, 读写锁通常会阻塞随后的读模式锁请求, 这样可以避免读模式锁⻓期占用, 而等待的写模式锁请求⻓期阻塞。 - 读写锁适合于对数据结构的读次数比写次数多得多的情况. 因为, 读模式锁定时变量与函数可以共享, 以写模式锁住时意味着独占, 所以读写锁又叫
共享-独占锁。
总结一下就是:
- 多读单写
- 写 和 写互斥
- 写 和 读互斥
- 读线程和进程的区别是什么、写 不能阻塞任务执行
栅栏函数 实现读写锁
@interface ViewController ()
@property (nonatomic, strong) dispatch_queue_t ssl_safeQueue;
@property (nonatomic, strong) NSMutableDictionary *mDict;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self ssl_safeSetter:@"111" time:4];
[self ssl_safeSetter:@"222" time:3];
[self ssl_safeSetter:@"333" time:2];
[self ssl_safeSetter:@"444" time:1];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
for (int i = 0; i < 10000; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"读取情况:%@ -- %d -- %@",[self ssl_safeGetter],i,[NSThread currentThread]);
});
}
}
- (void)ssl_safeSetter:(NSString *)name time:(int)time {
dispatch_barrier_async(self.ssl_safeQueue, ^{
sleep(time);
[self.mDict setValue:name forKey:@"ssl"];
NSLog(@"写情况:%@ - %@",self.mDict[@"ssl"],[NSThread currentThread]);
});
}
- (NSString *)ssl_safeGetter {
__block NSString *result;
dispatch_sync(self.ssl_safeQueue, ^{
result = self.mDict[@"ssl"];
});
return result;
}
- (dispatch_queue_t)ssl_safeQueue
{
if (!_ssl_safeQueue) {
_ssl_safeQueue = dispatch_queue_create("ssl", DISPATCH_QUEUE_CONCURRENT);
}
return _ssl_safeQueue;
}
- (NSMutableDictionary *)mDict
{
if (!_mDict) {
_mDict = [NSMutableDictionary new];
}
return _mDict;
}
@end
-
写操作中我们使用dispatch_barrier_async函数,使用这个函数前面的任务执行完才会执行这里,这里执安全教育平台登录行完才会执行后面的任务,这样可以达到写和写互斥的目的。 -
读操作也是放在了self.s初始化游戏启动器失败sl_safeQueue中,这样读和写互斥就完成了,也就真正意义的达成单写的目的,注意这里的dispatch_sync只是阻塞当前任务的线程,否则result就获取不到值了。 - 因为
self.ssl_safeQueue是并发队列,所以多读也是没问题的。

















评论(0)