iOS - 锁

作者: GA_ | 来源:发表于2020-06-18 21:57 被阅读0次

    OSSpinLock
    自旋锁(过期了),等待锁的线程会处于忙等(busy-wait)状态,一直占用着CPU资源
    目前应不再安全,可能出现优先级反转问题
    优先级低的线程1先进入,锁住。CPU把大量时间给优先级高的线程2,优先级高的线程2等线程1解锁,优先级低的线程获得不到CPU的时间,无法解锁。出现了假死锁。
    #import <libkern/OSAtomic.h>
    OSSpinLock lock = OS_SPINLOCK_INIT; // 需要全局 初始化一次
    // 锁
    OSSpinLockLock(&lock);
    // 解锁
    OSSpinLockUnLock(&lock);

    // 尝试加锁 
    if (OSSpinLockTry(&lock)) {
        OSSpinLockUnLock(&lock);
    }
    

    os_unfair_lock
    iOS10以后
    优化了OSSpinLock,等待os_unfair_lock锁的线程
    #import <os/lock.h>
    typedef struct os_unfair_lock_s {
    uint32_t _os_unfair_lock_opaque;
    } os_unfair_lock, *os_unfair_lock_t;

    @property(assign, nonatomic) os_Unfair_lock lock;
    
    os_unfair_lock_lock(&lock);
    os_unfair_lock_trylock(&lock);
    os_unfair_lock_unlock(&lock);
    

    pthread_mutex
    pthread开头都是跨平台的
    mutex:互斥
    互斥锁,等待锁的线程会处于休眠状态
    #import <pthread.h>
    // pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    // 初始化属性
    pthread_mutexattr_t attr;
    pthread_mutextattr_init(&attr);
    // PTHREAD_MUTEX_DEFAULT 默认锁
    // 检测错误锁
    // PTHREAD_MUTEX_RECURSIVE 递归锁
    允许同一个线程对一把锁进行重复加锁
    允许同一个线程先多次加锁,然后再解锁,加锁多少次,解锁多少次。
    a线程锁了,b线程来了要等待
    pthread_mutextattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
    // 初始化锁
    pthread_mutex_init(&mutex, &attr);
    // 销毁属性
    pthread_mutexattr_destroy(&attr);

    pthread_mutex_lock(&mutex);
    pthread_mutex_unlock(&mutex);
    
    // 销毁锁 (dealloc)
    phread_mutex_destroy(&mutex);
    
    - (void)test {
        pthread_mutex_lock(&mutex);    
        NSLog(@“—0”);
        [self test1];
    
        pthread_mutex_unlock(&mutex);
    }
    - (void)test1 {
        pthread_mutex_lock(&mutex);    
    
        NSLog(@“—1”);
    
        pthread_mutex_unlock(&mutex);
    }
    死锁,解决办法:两把锁,test1里再用一把锁mutex2即可
    

    - (void)test {
        pthread_mutex_lock(&mutex);    
        // 递归 使用PTHREAD_MUTEX_RECURSIVE
        static int count = 0;
        if (count < 5) {
            count++;
            [self test];
        }
    
        pthread_mutex_unlock(&mutex);
    }
    允许先多次加锁,然后再解锁,加锁多少次,解锁多少次。
    

    // 条件。
    @property(assign, nonatomic)pthread_cond_t cond;
    
    // 初始化
     pthread_cond_init(&cond, NULL);
    
    // 两条线程 先执行remove方法
    [[[NSTread alloc] initWithTarget:self selector:@selector(remove) objcet: nil] start];
    [[[NSTread alloc] initWithTarget:self selector:@selector(add) objcet: nil] start];
    
    - (void)remove {
        pthread_mutex_lock(&mutex);
        if (self.data.count == 0) {
            // 等待继续执行的条件cond 把mutex锁放开
            // 收到可以继续执行的条件 mutex加锁
            pthread_cond_wait(&cond, &mutex);
        }
        
        [self.data removeLastObject];
        NSLog(@“删除了元素”);
        
        pthread_mutex_unlock(&mutex);
    }
    
    - (void)add {
        pthread_mutex_lock(&mutex);
        sleep(1);
    
        [self.data addObject:@“te”];
        NSLog(@“添加了元素”);
        
        // 通知等待的cond 可以继续执行了
        pthread_cond_signal(&cond)
        
        pthread_mutex_unlock(&mutex);
    }
    

    NSLock
    对pthread_mutex普通锁的封装

    遵守NSLocking两个协议
        lock和unlock两个方法
    
    -(BOOL)tryLock; // 尝试加锁
    -(BOOL)lockBeforeDate: (NSDate *)limit; // 相比tryLock有个等待的时间 会阻塞
        在这个时间之前,能等到锁,就给这个锁加锁 加锁成功 继续往下走
        在时间内,没等到锁,加锁失败,代码继续往前走
    @property(strong, nonatomic) NSLock *lock;
    self.lock = [[NSLock allock] init];
    
    [self.lock lock];
    [self.lock unlock];
    

    NSRecursiveLock <NSLocking>
    对pthread_mutex递归锁锁的封装
    NSRecursiveLock方法同NSLock

    NSCondition<NSLocking>
    对pthread_cond_t的封装 有lock和unlock方法
    -(void)wait;
    -(BOOL)waitUntilDate:(NSDate *)limit;
    -(void)signal;
    -(void)broadcast;

    NSConditionLock<NSLocking>
    条件锁
    内部存储的条件之是1(初始化是多少)时候才能加锁
    对pthread_cond_t和pthread_mutex_t的封装

    @property(strong, nonatomic) NSConditionLock *conditionLock;
    
    self.conditionLock = [[NSConditonLock allok] initWithCondition:1];
    
    - (void)one {
        [self.conditionLock lockWhenCondition: 1];// 条件之为1才能加锁
        NSLog(@“11”);
        [self.conditionLock lockWhenCondition: 2];// 设置内部条件值为2 并解锁
    }
    
    - (void)two {
        [self.conditionLock lockWhenCondition: 3];// 条件之为2才能加锁
        NSLog(@“22”);
        [self.conditionLock unlock];    
    }
    - (void)three {
        [self.conditionLock lockWhenCondition: 3];// 条件之为2才能加锁
        NSLog(@“22”);
        [self.conditionLock unlock];    
    }
    效果:一定先执行one 再执行two 最后执行three
    

    dispatch_semaphore
    信号量 信号量的初始值,可以用来控制线程并发访问的最大数量
    最大并发量
    线程同步 信号量设置为1 DISPATCH_TIME_FOREVER 即可 保证只有一条线程执行
    @property (strong, nonatomic) dispatch_semaphore_t semaphore;

    self.semaphore = dispatch_semaphore_create(5); // 最大并发5
    
    - (void)test {
        for (i = 0; i< 20; i++) {
            [[[NSThread alloc] initWithTarget: self selector@selector(run) object:nil] start];
        }
    }
    
    - (void)run {
        // 信号量的值 > 0,就让信号量的值减1,然后继续执行代码
        // 信号量的值 <= 0 就会休眠等待 具体等多久 看dispatch_semaphore_wait第二个参数
        dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
        
        sleep(2);
        NSLog(@“%@“, [NSTread crrentThread]);
        
        // 刚执行到这里 信号量为0 
        // 信号量+1
        dispatch_semaphore_signal(self.semaphore);
    }
    

    // 每个方法都是独立一把锁
    -(void)test {
        static dispatch_semaphore_t semaphore;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^ {
            semaphore = dispatch_semaphore_create(1);
        })
    
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
        // 要加锁的代码        
    
        dispatch_semahore_signal(semaphore);
    }
    
    // 宏
    #define SemaphoreBegin \
    static dispatch_semaphore_t semaphore; \
    static dispatch_once_t onceToken; \
    dispatch_once(&onceToken, ^ { \
        semaphore = dispatch_semaphore_create(1); \
    })\ 
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    #define SemaphoreEnd \
        dispatch_semahore_signal(semaphore);
    
    -(void)test {
        SemaphoreBegin;
    
        // 要加锁的代码        
    
        SemaphoreEnd;
    }
    

    dispatch_queue(DISPATCH_QUEUE_SERIAL)
    串行队列
    @property(strong, nonatomic)dispatch_queue_t queue;

    self.queue = dispatch_queue_create(“q”, DISPATCH_QUEUE_SERIAL);
    
    - (void)saleTicket {
        dispatch_sync({self.queue, ^{
            NSLog(@“sale“);
        });
    }
    

    @synchronized
    对prhead_mutex递归锁的封装
    不推荐使用
    {
    @synchronized(self) {
    [self run];
    }
    }


    读写安全
    1、dispatch_semaphore_t 信号量
    读和写都给锁住了 读没必要锁住
    2、

    import <pthread.h>

    @property (assign, nonatomic)pthread_rwlock lock;

    {

    pthread_rwlock_init(&lock, NULL)    
    
    [[[NSTread alloc] initWithTarget:self selector:@selector(read) objcet: nil] start];
    [[[NSTread alloc] initWithTarget:self selector:@selector(write) objcet: nil] start];
    

    }

    -(void)read {
    pthread_rwlock_rdlock(&lock);
    NSLog(@“du”);
    pthread_rwlock_unlock(&lock);
    }

    -(void)write {
    pthread_rwlock_wrlock(&lock);
    NSLog(@“xie”);
    pthread_rwlock_unlock(&lock);
    }

    -(void)dealloc {
    pthread_rwlock_dispose(&lock);
    }


    -(void)read {
    dispatch_async(q, ^{
    NSLog(@“du”);
    })
    }

    -(void)write {
    dispatch_barrier_async(q, ^ {
    NSLog(@“xie”);
    })
    }

    相关文章

      网友评论

        本文标题:iOS - 锁

        本文链接:https://www.haomeiwen.com/subject/xpmpxktx.html