MJiOS底层笔记--多线程

本文属笔记性质,主要针对本身理解不太透彻的地方进行记录。

推荐系统直接学习小码哥iOS底层原理班---MJ老师的课确实不错,强推一波。ios


常见的多线程方案


线程的开辟与阻塞机制

  • 并行和串行主要影响:任务的执行方式

并行:多个任务并发(同时)执行 串行:一个任务执行完毕后,再执行下一个任务数组

  • 同步和异步主要影响:能不能开启新的线程

同步:在当前线程中执行任务,不具有开启新线程的能力 异步:在新的线程中执行任务,具有开启新线程的能力安全

  • 会开辟新线程的两种状况bash

    • 并行队列+异步任务 = 多条新线程
    • 自定义串行多列+异步任务 = 一条新线程
  • 其他状况、所有将会置于当前线程/主线程(主队列任务)下执行。多线程

GCD


多线程的安全隐患

资源抢夺

1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源并发

对共用资源的 读写进行枷锁操做


自旋锁

等待锁的线程会处于忙等(busy-wait)状态,一直占用着CPU资源异步

OSSpinLock

#import <libkern/OSAtomic.h>

@interface OSSpinLockDemo()
@property (assign, nonatomic) OSSpinLock lock;
@end

@implementation OSSpinLockDemo
- (instancetype)init
{
    if (self = [super init]) {
        self.lock = OS_SPINLOCK_INIT;
    }
    return self;
}


- (void)test
{
    OSSpinLockLock(&_lock);
    
    //同步操做
    
    OSSpinLockUnlock(&_lock);
}
@end

复制代码

优先级反转

OSSpinLock目前已经再也不安全,可能会出现优先级反转问题async

若是等待锁的线程优先级较高,它会一直占用着CPU资源,优先级低的线程就有可能得不到资源致使没法释放锁。性能


互斥锁(普通锁)

等待os_unfair_lock锁的线程会处于休眠状态,并不是忙等学习

os_unfair_lock

os_unfair_lock用于取代不安全的OSSpinLock ,从iOS10开始才支持

<os/lock.h>

@interface OSUnfairLockDemo()
@property (assign, nonatomic) os_unfair_lock lock;
@end

@implementation OSUnfairLockDemo

- (instancetype)init
{
    if (self = [super init]) {
        self.lock = OS_UNFAIR_LOCK_INIT;
    }
    return self;
}


- (void)__saleTicket
{
    os_unfair_lock_lock(&_lock);
    
    //耗时操做
    
    os_unfair_lock_unlock(&_lock);
}

@end
复制代码

pthread_mutex - PTHREAD_MUTEX_DEFAULT&&PTHREAD_MUTEX_NORMAL

PTHREAD_MUTEX_DEFAULT或PTHREAD_MUTEX_NORMAL下的 pthread_mutex 会产生互斥效果

NSLock

NSLock是对mutex普通锁的封装


递归锁

容许同一个线程对一把锁进行重复加锁

pthread_mutex - PTHREAD_MUTEX_RECURSIVE

PTHREAD_MUTEX_RECURSIVE 下的 pthread_mutex 会产生递归效果

NSRecursiveLock

NSRecursiveLock也是对mutex递归锁的封装,API跟NSLock基本一致

@synchronized

@synchronized是对mutex递归锁的封装

@synchronized(obj)内部会生成obj对应的递归锁并存在hash表中,而后进行加锁、解锁操做。性能最差

-(void)test {
    @synchronized(self) {
        NSLog(@"2");
        [self tess];
        sleep(5);
    }
}
复制代码

条件锁

可让一个线程在加锁途中等待另外一个线程完成某个动做后继续加锁执行

相似消费者在商场等着商家调货,而后继续购买。

在上锁状态下能够暂时将锁放开,休眠并等待某个条件

当其余线程对条件发送信号,唤醒继续加锁并执行

#### pthread_mutex - pthread_cond_t

@interface MutexDemo3()
@property (assign, nonatomic) pthread_mutex_t mutex;
@property (assign, nonatomic) pthread_cond_t cond;
@property (strong, nonatomic) NSMutableArray *data;
@end

@implementation MutexDemo3

- (instancetype)init
{
    if (self = [super init]) {
        // 初始化属性
        pthread_mutexattr_t attr;
        pthread_mutexattr_init(&attr);
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
        // 初始化锁
        pthread_mutex_init(&_mutex, &attr);
        // 销毁属性
        pthread_mutexattr_destroy(&attr);
        
        // 初始化条件
        pthread_cond_init(&_cond, NULL);
        
        self.data = [NSMutableArray array];
    }
    return self;
}

- (void)otherTest
{
    [[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start];
    
    [[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start];
}


// 线程1
// 删除数组中的元素
- (void)__remove
{
    pthread_mutex_lock(&_mutex);
    NSLog(@"__remove - begin");
    
    if (self.data.count == 0) {
        // 等待唤醒
        pthread_cond_wait(&_cond, &_mutex);
    }
    
    [self.data removeLastObject];
    NSLog(@"删除了元素");
    
    pthread_mutex_unlock(&_mutex);
}

// 线程2
// 往数组中添加元素
- (void)__add
{
    pthread_mutex_lock(&_mutex);
    
    sleep(1);
    
    [self.data addObject:@"Test"];
    NSLog(@"添加了元素");
    
    // 发送唤醒信号
    pthread_cond_signal(&_cond);

    
    pthread_mutex_unlock(&_mutex);
}

- (void)dealloc
{
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_cond);
}

@end

复制代码

NSCondition

NSCondition是对mutex和cond的封装

NSConditionLock

NSConditionLock是对NSCondition的进一步封装,能够设置具体的条件值

- (instancetype)init
{
    if (self = [super init]) {
        self.conditionLock = [[NSConditionLock alloc] initWithCondition:1];
    }
    return self;
}

- (void)otherTest
{
    [[[NSThread alloc] initWithTarget:self selector:@selector(__one) object:nil] start];
    
    [[[NSThread alloc] initWithTarget:self selector:@selector(__two) object:nil] start];
    
    [[[NSThread alloc] initWithTarget:self selector:@selector(__three) object:nil] start];
}

- (void)__one
{
    [self.conditionLock lock];
    
    NSLog(@"__one");
    sleep(1);
    
    [self.conditionLock unlockWithCondition:2];
}

- (void)__two
{
    [self.conditionLock lockWhenCondition:2];
    
    NSLog(@"__two");
    sleep(1);
    
    [self.conditionLock unlockWithCondition:3];
}
复制代码

dispatch_semaphore

信号量的初始值为1,表明同时只容许1条线程访问资源,保证线程同步

也能够控制线程的最大并发数

- (void)test
{
    // 若是信号量的值 > 0,就让信号量的值减1,而后继续往下执行代码
    // 若是信号量的值 <= 0,就会休眠等待,直到信号量的值变成>0,就让信号量的值减1,而后继续往下执行代码
    dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
    
    sleep(2);
    NSLog(@"test - %@", [NSThread currentThread]);
    
    // 让信号量的值+1
    dispatch_semaphore_signal(self.semaphore);
}
复制代码

性能排序

  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

自旋锁、互斥锁比较

什么状况使用自旋锁比较划算?

  1. 预计线程等待锁的时间很短
  2. 加锁的代码(临界区)常常被调用,但竞争状况不多发生
  3. CPU资源不紧张
  4. 多核处理器

什么状况使用互斥锁比较划算?

  1. 预计线程等待锁的时间较长
  2. 单核处理器
  3. 临界区有IO操做
  4. 临界区代码复杂或者循环量大
  5. 临界区竞争很是激烈

atomic

atomic用于保证属性setter、getter的原子性操做,至关于在getter和setter内部加了线程同步的锁

能够参考源码objc4的objc-accessors


iOS中的读写安全方案

读写锁

dispatch_barrier_async

@interface ViewController ()
@property (strong, nonatomic) dispatch_queue_t queue;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
//    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//    queue.maxConcurrentOperationCount = 5;
    
//    dispatch_semaphore_create(5);
    
    self.queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_CONCURRENT);
    
    for (int i = 0; i < 10; i++) {
        dispatch_async(self.queue, ^{
            [self read];
        });
        
        dispatch_async(self.queue, ^{
            [self read];
        });
        
        dispatch_async(self.queue, ^{
            [self read];
        });
        
        dispatch_barrier_async(self.queue, ^{
            [self write];
        });
    }
}


- (void)read {
    sleep(1);
    NSLog(@"read");
}

- (void)write
{
    sleep(1);
    NSLog(@"write");
}

@end
复制代码

pthread_rwlock_t

@interface ViewController ()
@property (assign, nonatomic) pthread_rwlock_t lock;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 初始化锁
    pthread_rwlock_init(&_lock, NULL);
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    for (int i = 0; i < 10; i++) {
        dispatch_async(queue, ^{
            [self read];
        });
        dispatch_async(queue, ^{
            [self write];
        });
    }
}


- (void)read {
    pthread_rwlock_rdlock(&_lock);
    
    sleep(1);
    NSLog(@"%s", __func__);
    
    pthread_rwlock_unlock(&_lock);
}

- (void)write
{
    pthread_rwlock_wrlock(&_lock);
    
    sleep(1);
    NSLog(@"%s", __func__);
    
    pthread_rwlock_unlock(&_lock);
}

- (void)dealloc
{
    pthread_rwlock_destroy(&_lock);
}


@end
复制代码
相关文章
相关标签/搜索