多线程只要分为4种:pthread、NSThread、GCD、NSOperation;通常我们使用的是后面3种。经常会使用到的就是GCD和NSOperation。
pthread:
用C语言写的、生命周期由程序员自己管理、基本上使用不到。
- 一套通用的多线程API;
- 适用于Unix、Linux、Windows等系统;
- 跨平台、可移植;
- 适用难度大;
NSThread:
用OC语言写的、生命周期由程序员自己管理、偶尔会使用到。
- 使用更加面向对象;
- 简单易用,可直接操作线程对象;
GCD:
用C语言写的、生命周期自动管理、经常使用。
- 用于替代NSThread等线程技术;
- 充分利用设备多核;
- 跨平台、可移植;
- 适用难度大;
NSOperation:
用OC语言写的、生命周期自动管理、经常使用。
- 基于GCD(底层是GCD);
- 比GCD多了一些简单实用的功能;
- 使用更加面向对象;
一、GCD的常用函数
1、同步线程(sync):只能是依次执行,不存才并发队列;(注意:不要炸当前串行队列中添加任务,会卡住当前串行队列,产生死锁。比如主线程(sync),中添加主队列任务)
通常使用的是dispathch_sync(dispathch_queue_t queue, dispathch_block_t block)
这个函数。
queue:就是队列;
block:就是你要做的事情,也就是任务;
2、异步线程(async):需要分为 并发队列 和 串行队列;
通常使用的是dispathch_async(dispathch_queue_t queue, dispathch_block_t block)
这个函数。
queue:就是队列;
block:就是你要做的事情,也就是任务;
- 同步和异步区别就在于是否具备开启新线程的能力。(注意:如果你在主队列,你还是一个一个执行,不会去开新的线程,就算是用主队列,也不会产生死锁)
- 在子线程中默认是没有开启RunLoop的。带有延迟、定时器,都是不会执行的。除非你打开RunLoop。
- (void)test {
NSLog(@"2");
}
dispathch_queue_t queue = dispathch_get_global_queue(0,0);
dispathch_async(queue, ^{
NSLog(@"1");
[self performSelector:@selector(test) withObject:nil afterDelay:.0];
NSLog(@"3");
}
这里的打印结果就是 1和3。延迟调用是在RunLoop里面的,默认子线程是没有开启子线程的。如果在主线里面是可以打印的,结果是132
dispathch_queue_t queue = dispathch_get_global_queue(0,0);
dispathch_async(queue, ^{
NSLog(@"1");
// [self performSelector:@selector(test) withObject:nil];
// 这两个是不一样的,这个是objc_msgsend里面的
[self performSelector:@selector(test) withObject:nil afterDelay:.0];
NSLog(@"3");
// 这个可以不要,上面的方法是在RunLoop里面添加了定时器的。
[[NSRunLoop currrentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
这个打印的结果就是132
3、并发队列:多个任务同时执行。
4、串行队列(FIFO先进先出):一个任务执行完之后,才能执行下一个任务。
队列决定一个一个执行,还是多个一起执行。
点击查看GCD源码
思考:使用GCD实现:
异步并发执行 任务1、任务2;
等 任务1、任务2 完成之后再回到主线程执行 任务3。
// 创建队列组
dispathch_group_t group = dispathch_group_create();
// 创建并发队列
dispathch_queue_t queue = dispathch_queue_create("my_queue", DISPATHCH_CONCURRENT);
dispathch_group_async(group, queue, ^{
for(init i = 0; i<5; i++) {
NSLog(@"任务1-%@", [NSThread currentThread]);
}
}
dispathch_group_async(group, queue, ^{
for(init i = 0; i<5; i++) {
NSLog(@"任务2-%@", [NSThread currentThread]);
}
}
// 等前面任务完成之后,会自动执行这个任务
dispathch_group_notify(group, dispathch_get_main_queue(), ^{
for(init i = 0; i<5; i++) {
NSLog(@"任务3-%@", [NSThread currentThread]);
}
}
二、多线程的安全问题
- 资源共享
- 一个资源被多个线程共享,也就是多个线程可能会访问同一个资源;
- 比如:多个线程访问同一个对象,同一个变量,同一个文件;
- 当多个线程访问同一块资源时,很容易引发 数据错乱 和 数据安全 问题
解决方案:
- 使用 线程同步 技术(同步,就是协同步调,按预定的先后次序进行运行);
- 常见的线程同步技术是:加锁;
-
OSSpinLock
:自旋锁。等带锁的线程会处于忙等(busy-wait
)状态,一直占用着CPU
资源;线程不安全,优先级反转。 -
os_unfair_lock
:互斥锁,用来替换自旋锁。处于休眠状态,不是忙等状态。 -
pthread_mutex
:跨平台。等待锁的线程会处于休眠状态。 -
dispathch_semaphore
:信号量,用来控制线程并发量。值为1,可以保证线程同步 -
dispathch_queue(DISPATHCH_QUEUE_SERIAL)
:GCD
同步队列,也可以保证线程同步 -
NSLock
:对mutex普通锁的封装。 -
NSRecursiveLock
:对mutex
的 *递归锁 封装。API
和NSLock
基本一致。 -
NSCondition
:对mutex和condition的封装。条件锁。 -
NSCondtionLock
:对NSCondition
的进一步封装,可以设置具体的条件值。条件值为1,也可以保证线程同步。 -
@synchronized
:对mutex
递归锁的封装,Apple不推荐使用,性能比较差。
性能从高到低排序
os_unfair_lock
:iOS10以后,推荐使用- OSSpinLock
dispatch_semaphore
:推荐使用pthread_mutex
:推荐使用- dispatch_queue(DISPATCH_QUEUE_SERIAL)
- NSLock
- NSCondition
- pthread_mutex(recursive)
- NSRecursiveLock
- NSConditionLock
- @synchronized
我们想写一个基类MJBaseDemo
MJBaseMode.h
#import
@interface MJbaseMode : NSObject
- (void)moneyTest;
- (void)ticketTest;
#pragma mark - 暴露给子类去使用
- (void)__saveMoney;
- (void)__drawMoney;
- (void)__saleTicket;
@end
MJBaseMode.m
#import "MJBaseDemo.h"
@interface MJBaseDemo()
@property (assign, nonatomic) int money;
@property (assign, nonatomic) int ticketsCount;
@end
@implementation MJBaseDemo
/** 卖票演示 */
- (void)ticketTest
{
self.ticketsCount = 15;
dispathch_queue_t queue = dispathch_get_global_queue(0,0);
dispathch_async(queue, ^{
for (int i = 0; i < 5; ++i)
{
[self saleTicket];
}
}
dispathch_async(queue, ^{
for (int i = 0; i < 5; ++i)
{
[self saleTicket];
}
}
dispathch_async(queue, ^{
for (int i = 0; i < 5; ++i)
{
[self saleTicket];
}
}
}
- (void)monyeTest
{
self.money = 100;
dispathch_queue_t queue = dispathch_get_global_queue(0,0);
dispathch_async(queue, ^{
for (int i = 0; i < 10; ++i)
{
[self saveMoney];
}
}
dispathch_async(queue, ^{
for (int i = 0; i < 10; ++i)
{
[self drawMoney];
}
}
// 卖票
- (void)__saleTicket
{
sleep(.2);
self.ticketsCount --;
NSLog(@"卖出一张票,还剩%d张----%@", self.ticketsCount, [NSThread currentThread]);
}
// 取钱
- (void)__drawMoney
{
sleep(.2);
self.money -= 20;
NSLog(@"取钱20,还剩%d元----%@", self.money, [NSThread currentThread]);
}
// 存钱
- (void)__saveMoney
{
sleep(.2);
self.money += 50;
NSLog(@"存钱50,还剩%d元----%@", self.money, [NSThread currentThread]);
}
@end
1、OSSpinLock:不推荐使用,效率还是很高的。
- 等带锁的线程会处于忙等(
busy-wait
)状态,一直占用着CPU
资源; - 需要导入头文件
#import
- 目前已经不再安全, 可能会出现优先级反转问题;
- 如果等待锁的线程优先级比较高,他会一直占用
CPU
资源,优先级低的线程无法释放锁;
- 如果等待锁的线程优先级比较高,他会一直占用
OSSpinLockDemo.h
#import "MJBaseDemo.h"
@interface OSSpinLockDemo : MJBaseDemo
@end
OSSpinLockDemo.m
#import "OSSpinLockDemo.h"
#import
static OSSpinLock moneyLock_;
static OSSpinLock ticketLock_;
@interface OSSpinLockDemo()
// @property (assign, nonatomic) OSSpinLock moneyLock;
// @property (assign, nonatomic) OSSpinLock ticketLock;
@end
@implementation OSSpinLockDemo
+ (void)initialize {
static dispathch_once_t onceToken;
dispathch_once(&onceToken, ^{
moneyLock_ = OS_SPINLOCK_INIT;
ticketLock_ = OS_SPINLOCK_INIT;
});
}
- (void)__saveMoney {
OSSpinLockLock(&moneyLock_);
[super __saveMoney];
OSSpinLockUnlock(&moneyLock_);
}
- (void)__drawMoney {
OSSpinLockLock(&moneyLock_);
[super __drawMoney];
OSSpinLockUnlock(&moneyLock_);
}
- (void)__saleTicket {
OSSpinLockLock(&ticketLock_);
[super __saleTicket];
OSSpinLockUnlock(&ticketLock_);
}
@end
viewController.m
#import "ViewController.h"
#import "MJBaseDemo.h"
#import "MJOSSpinLock.h"
#import "OSSpinLockDemo.h"
@interface ViewController()
@property (strong, nonatomic) MJBaseDemo * demo;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
MJBaseDemo * demo = [[OSSpinLockDemo alloc] init];
[demo ticketTest];
[demo moneyTest];
}
@end
2、os_unfair_lock:用于取代不安全的OSSpinLock
, 从iOS10
开始才支持。(Low-level lock低级锁会去休眠,可以看做互斥锁)
- 从底层调用来看,等待
os_unfair_lock
锁的线程处于休眠状态,并不忙等。 - 需要导入头文件
#import
- 这个不是 “自旋锁”,等待的线程会自动跳过,休眠,应该叫“互斥锁”
用法给OSSpinLoc
k一样,只是头文件,和名字不一样。
如果os_unfair_look
忘记解锁了,就会变成死锁。
SOUnfairLockDemo.h
#import "MJBaseDemo.h"
@interface SOUnfairLockDemo : MJBaseDemo
@end
SOUnfairLockDemo.m
#import "OSUnfairLockDemo.h"
#import
static os_unfair_lock moneyLock_;
static os_unfair_lock ticketLock_;
@implementation OSUnfairLockDemo
+ (void)initialize {
static dispathch_once_t onceToken;
dispathch_once(&onceToken, ^{
moneyLock_ = OS_UNFAIR_LOCK_INIT;
ticketLock_ = OS_UNFAIR_LOCK_INIT;
});
}
- (void)__saveMoney {
os_unfair_lock_lock(&moneyLock_);
[super __saveMoney];
os_unfair_lock_unlock(&moneyLock_);
}
- (void)__drawMoney {
os_unfair_lock_lock(&moneyLock_);
[super __drawMoney];
os_unfair_lock_unlock(&moneyLock_);
}
- (void)__saleTicket {
os_unfair_lock_lock(&ticketLock_);
[super __saleTicket];
os_unfair_lock_unlock(&ticketLock_);
}
@end
viewController.m
#import "ViewController.h"
#import "MJBaseDemo.h"
#import "SOUnfairLockDemo.h"
@interface ViewController()
@property (strong, nonatomic) MJBaseDemo * demo;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
MJBaseDemo * demo = [[SOUnfairLockDemo alloc] init];
[demo ticketTest];
[demo moneyTest];
}
@end
3、pthread_mutext:互斥锁,等待锁的线程会处于休眠状态。
- 需要导入头文件
#import
; - 需要消耗属性设置,销毁锁;
- 如果你是递归,或者重复使用一个锁,设置属性的时候,你选择递归锁(允许同一个线程使用同一把锁,第二个线程进入时,会等待第一个线程,完成之后,才会执行,去加锁;不会被第二个线程调用)
#import "MutexDemo.h"
#import
@interface MutexDemo()
@property (assign, nonatomic) pthread_mutex_t ticketMutex;
@property (assign, nonatomic) pthread_mutex_t moneyMutex;
@property (assign, nonatomic) pthread_mutex_t mutex;
@end
@implementation MutexDemo
- (void)__initMutex:(pthread_mutex_t *)mutex {
// 初始化属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHEAD_MUTEX_DEFAULT);
// 初始化锁
pthread_mutex_init(mutex, &attr);
// 销毁锁
pthread_mutexattr_destroy(&attr);
// 上面的可以替换
// pthread_mutex_init(mutex, NULL);
// 这个就是默认属性
}
- (void)__initMutex_recursive:(pthread_mutex_t *)mutex {
// 初始化属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHEAD_MUTEX_RECURSIVE);
// 初始化锁
pthread_mutex_init(mutex, &attr);
// 销毁锁
pthread_mutexattr_destroy(&attr);
// PTHEAD_MUTEX_RECURSIVE 递归锁
// 同一个线程会使用同一把锁,
// 第二个线程进入时,会等待第一个线程,完成之后,才会执行,去加锁;
// 不会被第二个线程调用。
// PTHEAD_MUTEX_REEORCHECK 报错锁
// PTHEAD_MUTEX_DEFAULT == PTHEAD_MUTEX_NORMAL 普通锁
}
- (instancetype)init {
if (self = [super init])
{
[self __initMutex:&self.ticketMutex];
[self __initMutex:&self.moneyMutex];
[self __initMutex_recursive:&self.mutex];
}
return self;
}
- (void)__saveMoney {
pthread_mutex_lock(&self.moneyMutex);
[super __saveMoney];
pthread_mutex_unlock(&self.moneyMutex);
}
- (void)__drawMoney {
pthread_mutex_lock(&self.moneyMutex);
[super __drawMoney];
pthread_mutex_unlock(&self.moneyMutex);
}
- (void)__saleTicket {
pthread_mutex_lock(&self.moneyMutex);
[super __saleTicket];
pthread_mutex_unlock(&self.moneyMutex);
}
- (void)otherTest {
pthread_mutex_lock(&self.mutex);
NSLog(@"@s", __func__);
[self otherTest2];
pthread_mutex_unlock(&self.mutex);
}
- (void)otherTest2 {
pthread_mutex_lock(&self.mutex);
NSLog(@"@s", __func__);
pthread_mutex_unlock(&self.mutex);
}
- (void)dealloc {
pthread_mutex_distroy(&slef.moneyMutex);
pthread_mutex_distroy(&slef.ticketMutex);
pthread_mutex_distroy(&slef.mutex);
}
@end
ViewController.m
#import "ViewController.h"
#import "MJBaseDemo.h"
#import "MJOSSpinLock.h"
#import "OSSpinLockDemo.h"
#import "OSUnfairLock.h"
#import "MutexDemo.h"
@interface ViewController()
@property (strong, nonatomic) MJBaseDemo * demo;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// MJBaseDemo * demo = [[OSSpinLockDemo alloc] init];
// MJBaseDemo * demo = [[OSUnfairLock alloc] init];
MJBaseDemo * demo = [[MutexDemo alloc] init];
[demo ticketTest];
[demo moneyTest];
[demo otherTest];
}
@end
3-1、pthread_mutext:条件。
#import "MutexDemo.h"
#import
@interface MutexDemo()
@property (assign, nonatomic) pthread_mutex_t condMutex;
@property (assign, nonatomic) pthread_cond_t cond;
@property (strong, nonatomic) NSMutableArray data;
@end
@implementation MutexDemo
- (instancetype)init {
if (self = [super init])
{
// 初始化属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHEAD_MUTEX_RECURSIVE);
// 初始化锁
pthread_mutex_init(mutex, &attr);
// 销毁锁
pthread_mutexattr_destroy(&attr);
// 初始化条件
pthread_cond_init(&self.cond, NULL);
self.data = [NSMutableArray array];
}
return self;
}
- (void)__add {
pthread_mutex_lock(&self.condMutex);
sleep(1);
[self.data addObject:@"test"];
NSLog(@"添加元素");
// 发信号
pthread_cond_signal(&self.cond);
// 发广播,这个用于多线程,一次唤醒多个线程
// pthread_cond_boradcast(&self.cond);
pthread_mutex_unlock(&self.condMutex);
}
- (void)__remove {
pthread_mutex_lock(&self.condMutex);
NSLog(@"__remove - begin");
if (self.data.count == 0)
{
pthread_cond_wait(&self.cond, &self.condMutex);
}
[self.data removeLastObject];
NSLog(@"删除元素");
pthread_mutex_unlock(&self.condMutex);
}
- (void)dealloc {
pthread_mutex_destroy(&slef.condMutex);
pthread_cond_destroy(&self.cond)
}
@end
4、NSLock :互斥锁。对pthead_mutext_t的封装,PTHREAD_MUTEX_NORMAL
#import "NSLockDemo.h"
@interface NSLockDemo()
@property (strong, nonatomic) NSLock * moneyLock;
@property (strong, nonatomic) NSLock * ticketLock;
@end
@implementation NSLockDemo
- (instancetype)init {
if (self = [super init])
{
// 相当于 pthread_mutext_init(&mutex,NULL)
self.moneyLock = [[NSLock alloc] init];
self.moneyLock = [[NSLock alloc] init];
}
return self;
}
- (void)__saveMoney {
[self.moneyLock lock];
[super __saveMoney];
[self.moneyLock unlock];
}
- (void)__drawMoney {
[self.moneyLock lock];
[super __drawMoney];
[self.moneyLock unlock];
}
- (void)__saleTicket {
[self.ticketLock lock];
[super __saleTicket];
[self.ticketLock unlock];
}
@end
5、NSRecursiveLock:互斥锁。对pthead_mutext_t的封装,PTHREAD_MUTEX_RECURSIVE
- 使用和NSLock一致。
6、NSCondition:条件。对mutext和cond的封装
#import "NSContitionDemo.h"
@interface NSContitionDemo()
@property (strong, nonatomic) NSCondition* condition;
@property (strong, nonatomic) NSMutableArray data;
@end
@implementation NSContitionDemo
- (instancetype)init {
if (self = [super init])
{
self.condition = [[NSCondition alloc] init];
self.data = [NSMutableArray array];
}
return self;
}
- (void)__add {
[self.condition lock];
sleep(1);
[self.data addObject:@"test"];
NSLog(@"添加元素");
[self.condition unlock];
// 发信号
[self.condition signal];
// 广播
// 【self.condition broadcast];
}
- (void)__remove {
[self.condition lock];
NSLog(@"__remove - begin");
if (self.data.count == 0)
{
[self.condition wait];
}
[self.data removeLastObject];
NSLog(@"删除元素");
[self.condition unlock];
}
@end
7、NSConditionLock:条件。对NSCondition的进一步封装,可以设置条件
#import "NSContitionLockDemo.h"
@interface NSContitionLockDemo()
@property (strong, nonatomic) NSConditionLock * conditionLock;
@end
@implementation NSContitionLockDemo
- (instancetype)init {
if (self = [super init])
{
// 创建一个锁,条件为1
self.conditionLock = [[NSConditionLock alloc] initWithCondition:1];
}
return self;
}
- (void)test {
// 这里会先执行条件为1的锁,所在的线程
[[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start];
}
- (void)__add {
// 当条件为1时,加锁
[self.conditionLock lockWhenCondition:1];
NSLog(@"添加元素");
// 解锁,修改条件为2
[self.conditionLock unlockWithCondition:2];
}
- (void)__remove {
// 当条件为2时,加锁
[self.conditionLock lockWhenCondition:2];
NSLog(@"删除元素");
[self.conditionLock unlock];
}
@end
8、SerialQueue:同步串行队列,也能保证线程同步。
#import "SerialQueueDemo.h"
@interface SerialQueueDemo()
@property (strong, nonatomic) dispathch_queue_t moneyQueue;
@property (strong, nonatomic) dispathch_queue_t * ticketQueue;
@end
@implementation SerialQueueDemo
- (instancetype)init {
if (self = [super init])
{
// 相当于 pthread_mutext_init(&mutex,NULL)
self.moneyQueue = [dispathch_queue_create("moneyQueue", DISPATHCH_QUEUE_SERIAL)];
self.ticketQueue = [dispathch_queue_create("ticketQueue", DISPATHCH_QUEUE_SERIAL)];
}
return self;
}
- (void)__saveMoney {
dispathch_sync(self.moneyQueue, ^{
[super __saveMoney];
});
}
- (void)__drawMoney {
dispathch_sync(self.moneyQueue, ^{
[super __drawMoney];
});
}
- (void)__saleTicket {
dispathch_sync(self.ticketQueue, ^{
[super __saleTicket];
});
}
@end
9、dispathch_semaphore:信号量。
- 信号量的初始值,可以用来控制线程并发访问的最大数量。
- 如果信号量的值为1,也是能保证线程同步的。
#import "SemaphoreDemo.h"
@interface SemaphoreDemo()
@property (strong, nonatomic) dispthch_semaphore_t semaphore;
@end
@implementation SemaphoreDemo
- (instancetype)init {
if (self = [super init])
{
// 最多只有5个线程执行任务。
self.semaphore = dispthch_semaphore_create(5);
}
return self;
}
- (void)otherTest {
// 同时开20个线程做一个事情
for (int i = 0; i < 20; i++)
{
[[[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil] start];
}
}
- (void)test {
// 如果信号量的值 > 0,就让信号量的值减1,然后继续往下执行代码
// 如果信号量 <= 0,就会休眠,直到信号量的值 > 0,去抢到这个信号,接着继续让信号量的值减1, 然后继续往下执行代码
dispthch_semaphore_wait(self.semaphore, DISPATHCH_TIME_FOREVER);
sleep(1);
NSLog(@"test---%@", [NSThread currentThread]);
// 信号量的值 +1
dispthch_semaphore_signal(self.semaphore);
}
@end
10、@synchronized:对mutex递归锁的封装
- 性能比较差,官方不推荐使用。
#import "SerialQueueDemo.h"
@implementation SerialQueueDemo
- (void)__saveMoney {
// 确保self是同一个对象,才有加锁的功能。也可是类对象,[self class]
@synchronized(self) {
[super __saveMoney];
}
}
- (void)__drawMoney {
@synchronized(self) {
[super __drawMoney];
}
}
- (void)__saleTicket {
static NSObjec * lock;
static dispathch_once_t onceToken;
dispathch_once(&onceToken, ^{
lock = [[NSObjec alloc] init];
});
@synchronized(lock) {
[super __saleTicket];
}
}
@end
使用技巧,通过宏来简便使用。
#define SemaphoreBegin \
static dispathch_semaphore_t semaphore; \
static dispathch_once_t onceToken; \
dispathch_once(&onceToken, ^{ \
semaphore = dispathch_semaphore_create(1); \
}); \
dispathch_semaphore_wait(semaphore, DISPATHCH_TIME_FOREVER);
#define SemaphoreeEnd \
dispathch_semaphore_signal(semaphore);
- (void)test {
SemaphoreBegin;
// ......do things......
SemaphoreeEnd;
}
11、自旋锁和互斥锁比较
- 什么情况使用自旋锁比较划算?
- 预计线程等待锁的时间比较短;
- 加锁的代码经常使用,但是竞争情况很少发生;
- CPU资源不紧张;
- 多核处理器。
- 什么情况使用互斥锁比较划算?
- 预计线程等待时间长,2s+;
- 单核处理器;
- 临界区(锁里面的开始代码,和结束代码)有I/O操作;
- 临界区代码复杂或者循环量大;
- 临界区竞争非常激烈。
12、I/O操作,文件操作、读写安全
- 从文件中读取内容;
- 往文件中写入内容;
方案: - 同一时间,只能有1线程进行写的操作
- 同一时间,允许多个线程进行操作
- 同一时间,不允许既有写的操作,又有读的操作。
dispathch_rwlock:跨平台,读写锁
- 等待锁的线程会进入睡眠;
#import "pthreadRwlockDemo.h"
@interface pthreadRwlockDemo()
@property (assign, nonatomic) pthread_rwlock_t lock;
@end
@implementation pthreadRwlockDemo
- (void)viewDidLoad {
[super viewDidLoad];
pthread_rwlock_init(&self.lock, NULL);
dispathch_queue_t queue = dispathch_get_global_queue(0,0);
for (int i = 0; i < 10; ++i)
{
dispathch_async(queue, ^{
[self read];
});
dispathch_async(queue, ^{
[self write];
});
}
}
- (void)read {
pthread_rwlock_rdlock(&self.lock);
sleep(1);
NSLog(@"%s", __func__);
pthread_rwlock_unlock(&self.lock);
}
- (void)write {
pthread_rwlock_wrlock(&self.lock);
sleep(1);
NSLog(@"%s", __func__);
pthread_rwlock_unlock(&self.lock);
}
- (void)dealloc {
pthread_rwlock_destroy(&self.lock);
}
@end
dispathch_barrier_async:跨平台,读写锁
- 这个函数传入的并发队列
必须
是自己通过dispathch_queue_create
创建; - 如果传入是一个串行或者是一个全局的并发队列,那这个函数等同于dispathch_async函数的效果;
#import "pthreadBarrierDemo.h"
@interface pthreadBarrierDemo()
@property (strong, nonatomic) dispathch_queue_t queue;
@end
@implementation pthreadBarrierDemo
- (void)viewDidLoad {
[super viewDidLoad];
// 并发队列
self.queue = dispathch_queue_create("rw_queue", DISPATHCH_QUEUE_CONCURRENT);
for (int i = 0; i < 10; i++)
{
dispathch_async(queue, ^{
[self read];
[self read];
});
dispathch_barrier_async(queue, ^{
[self write];
});
}
}
- (void)read {
sleep(1);
NSLog(@"%s", __func__);
}
- (void)write {
sleep(1);
NSLog(@"%s", __func__);
}
@end