OC底层基础:多线程GCD

2022-02-23  本文已影响0人  节奏lhl

查看oc文件底层结构

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc xxx.m

支持ARC、指定运行时系统版本

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-15.0.0 xxx.m

一、iOS中常见的多线程方案

iOS中常见的多线程方案.png

二、容易混淆的术语

有4种术语比较容易混淆:同步、异步、并发、串行

注:使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列(产生死锁)

三、GCD的常用函数

1. GCD中2个用来执行任务的函数

注:queue:队列,block:队列

2. GCD源码:https://github.com/apple/swift-corelibs-libdispatch

四、线程同步方案

OSSpinLock(iOS10之后废弃)

// 初始化
OSSpinLock lock = OS_SPINLOCK_INIT;
// 尝试加锁(如果需要等待就不加锁,直接返回false;如果不需要等待就加锁,返回true)
bool result = OSSpinLockTry(&lock);
// 加锁
OSSpinLockLock(&lock);
// 解锁
OSSpinLockUnlock(&lock);

os_unfair_lock

/// 初始化
os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
/// 尝试加锁
os_unfair_lock_trylock(&lock);
/// 加锁
os_unfair_lock_lock(&lock);
/// 解锁
os_unfair_lock_unlock(&lock);

dispatch_semaphore

// 信号量的初始化
int value = 1;
// 初始化信号量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(value);
// 如果信号量的值<=0,当前线程就会进入休眠等待(直到信号量的值>0)
// 如果信号量的值>0,就减1,然后往下执行后面的代码
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//让信号量的值加1
dispatch_semaphore_signal(semaphore);

pthread_mutex

// 初始化锁的属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
// pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ RECURSIVE);(递归锁:允许同一个线程对一把锁进行重复加锁)
// 初始化锁
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, &attr);
// 尝试加锁
pthread_mutex_trylock(&mutex);
// 加锁
pthread_mutex_lock(&mutex);
// 解锁
pthread_mutex_unlock(&mutex);
// 销毁相关资源
pthread_mutexattr_destroy(&attr);
pthread_mutex_destroy(&mutex);

/*
 * Mutex type attributes
 */
#define PTHREAD_MUTEX_NORMAL        0
#define PTHREAD_MUTEX_ERRORCHECK    1
#define PTHREAD_MUTEX_RECURSIVE     2
#define PTHREAD_MUTEX_DEFAULT       PTHREAD_MUTEX_NORMAL

NSLock、NSRecursiveLock

@interface NSLock : NSObject <NSLocking> {
- (BOOL)tryLock;
- (BOOL)lockBeforeDate:(NSDate *)limit;
@end

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

// 初始化锁
NSLock *lock = [[NSLock alloc] init];

NSCondition

@interface NSCondition : NSObject <NSLocking> {
- (void)wait;
- (BOOL)waitUntilDate:(NSDate *)limit;
- (void)signal;
- (void)broadcast;
@end

pthread_mutex - 条件(条件锁)

// 初始化锁
pthread_mutex_t mutex;
// NULL代表使用默认属性
pthread_mutex_init(&mutex, NULL);
// 初始化条件
pthread_cond_t condition;
pthread_cond_init(&condition, NULL);
// 等待条件(进入休眠,开放mutex锁;被唤醒后,会再次对mutex加锁)
pthread_cond_wait(&condition, &mutex);
// 激活一个等待该条件的线程
pthread_cond_signal(&condition);
// 激活所有等待该条件的线程
pthread_cond_broadcast(&condition);
// 销毁相关资源
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&condition);

NSConditionLock

@interface NSConditionLock : NSObject <NSLocking> {
- (instancetype)initWithCondition:(NSInteger)condition NS_DESIGNATED_INITIALIZER;
@property (readonly) NSInteger condition;
- (void)lockWhenCondition:(NSInteger)condition;
- (BOOL)tryLock;
- (BOOL)tryLockWhenCondition:(NSInteger)condition;
- (void)unlockWithCondition:(NSInteger)condition;
- (BOOL)lockBeforeDate:(NSDate *)limit;
- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;
@end

dispatch_queue

@synchronized

性能从高到低排序

  1. os_unfair_lock
  2. OSSpinLock
  3. dispatch_semaphore
  4. pthread_mutex
  5. dispatch_queue(DISPATCH_QUEUE_SERIAL)
  6. NSLock
  7. NSCondition
  8. pthread_mutex(recursive)
  9. NSRecursiveLock
  10. NSConditionLock
  11. @synchronized

五、多线程安全隐患的解决方案

六、自旋锁、互斥锁比较

七、iOS中读写安全方案

思考如何实现以下场景

上面的场景是典型的”多读单写“,经常用于文件等数据的读写操作,iOS中实现方案有

pthread_rwlock

// 初始化锁
pthread_rwlock_t *lock;
pthread_rwlock_init(&lock, NULL);
// 读-加锁
pthread_rwlock_rdlock(&lock);
// 读-尝试加锁
pthread_rwlock_tryrdlock(&lock);
// 写-加锁
pthread_rwlock_wrlock(&lock);
// 写-尝试加锁
pthread_rwlock_wrlock(&lock); 
// 解锁
pthread_rwlock_unlock(&lock);
// 销毁
pthread_rwlock_destroy(&lock);

dispatch_barrier_async

// 初始化队列
dispatch_queue_t queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_CONCURRENT);
// 读
dispatch_async(queue, ^{
});
// 写
dispatch_barrier_sync(queue, ^{
});

八、其他

atomic

面试题

dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
    NSLog(@"1");
    [self performSelector:@selector(test) withObject:nil afterDelay:0];
    NSLog(@"3");
});

- (void)test {
    NSLog(@"2");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSThread *thread = [[NSThread alloc] initWithBlock:^{
        NSLog(@"1");
    }];
    [thread start];
    
    [self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:YES];
}

- (void)test {
    NSLog(@"2");
}

如何用GCD实现

  1. 异步并发执行任务1、任务2
  2. 等任务1、任务2执行完毕后,再回到主线程执行任务3
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(group, queue, ^{
        NSLog(@"任务1");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"任务2");
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"任务3");
    });

注:可能涉及的面试题

上一篇:
OC底层基础:RunLoop
下一篇:
OC底层基础:内存管理

上一篇 下一篇

猜你喜欢

热点阅读