IOS多线程安全(线程锁)

2019-12-03  本文已影响0人  迷失的信徒

线程安全

线程的不安全是由于多线程访问和修改共享资源而引起的不可预测的结果。
ios多线程开发中为保证线程的安全常用到的几种锁:NSLockdispatch_semaphoreNSConditionNSRecursiveLock@synchronized

WEAKSELF typeof(self) __weak weakSelf = self;

1.NSLock

NSLock 是OC层封装底层线程操作来实现的一种锁,继承NSLocking协议。不能迭代加锁,如果发生两次lock,而未unlock过,则会产生死锁问题。
以车站购票为例,多个窗口同时售票(同步),每个窗口有人循环购票:

// 加锁
[lock lock];
/*
* 被加锁的代码区间
*/
// 解锁
[lock Unlock];
/*******************************************************************************/
//lock--unlock 、tryLuck---unLock  必须成对存在
_num = 50;//总票数
_lock = [[NSLock alloc] init];
dispatch_queue_t queue = dispatch_queue_create("delayQueue", DISPATCH_QUEUE_CONCURRENT);
    for (NSInteger time = 0; time < 10; time++) {

        dispatch_async(queue, ^{
            
            [weakSelf testNSLock];
        });
    }
/*******************************************************************************/
//测试方法
- (void)testNSLock
{
    while (1) {
        [_lock lock];
        if (_num > 0) {
            _num--;
            NSLog(@"--->> %@已购票1张,剩余%ld张", [NSThread currentThread], (long)_num);
        }else{
            [_lock unlock];
            return;
        }
        [_lock unlock];
        sleep(0.2);
    }
}
/*******************************************************************************/
//当前线程锁失败,也可以继续其它任务,用 trylock 合适
-(void)myLockTest1{
    if ([mylock tryLock]) {
        // to do something
        [mylock unlock];
    }
}
//当前线程只有锁成功后,才会做一些有意义的工作,那就lock,没必要轮询trylock
-(void)myLockTest2{
    [mylock lock];
    // to do something
    [mylock unlock];
}

2.@synchronized

_num = 50;//总票数
dispatch_queue_t queue = dispatch_queue_create("delayQueue", DISPATCH_QUEUE_CONCURRENT);
    for (NSInteger time = 0; time < 10; time++) {
        dispatch_async(queue, ^{
            while (1) {
                @synchronized (weakSelf) {
                    if (weakSelf->_num > 0) {
                        weakSelf->_num--;
                        NSLog(@"--->> %@已购票1张,剩余%ld张", [NSThread currentThread], (long)weakSelf->_num);
                    }else{
                        return ;
                    }
                }
            }
        });
    }

原子操作
原子操作是指不可打断的操作,也就是说线程在执行操作的过程中,不会被操作系统挂起,而是一定会执行完,
变量属性Property中的原子定义
一般我们定义一个变量@property (nonatomic ,strong)NSLock *lock;nonatomic:非原子性,不会为setter方法加锁,适合内存小的移动设备;atomic:原子性,默认为setter方法加锁(默认就是atomic),线程安全。
PS: 在iOS开发过程中,一般都将属性声明为nonatomic,尽量避免多线程抢夺同一资源,尽量将加锁等资源抢夺业务交给服务器。

3NSRecursiveLock

_num = 50;//总票数
_lock = [[NSRecursiveLock alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
        static void (^MyRecursiveLockBlock)(NSInteger value);
        MyRecursiveLockBlock = ^(NSInteger value){
            [weakSelf.lock lock];
                if (value > 0) {
                    weakSelf.num--;
                    NSLog(@"--->> %@已购票1张,剩余%ld张", [NSThread currentThread], (long)weakSelf.num);
                    MyRecursiveLockBlock(value - 1);
                }
            [weakSelf.lock unlock];
            };
            MyRecursiveLockBlock(weakSelf.num);
    });

4.NSCondition

NSCondition常用于生产者-消费者模式,它继承了NSLocking协议,同样有lock和unlock方法。条件变量有点像信号量,提供了线程阻塞和信号机制,因此可以用来阻塞某个线程,并等待数据就绪再唤醒程序。

@property (nonatomic ,strong)NSCondition *lock;
@property (nonatomic ,strong)NSMutableArray *array;
- (void)viewDidLoad
{
    typeof(self) __weak weakSelf = self;
    _lock = [[NSCondition alloc] init];
    
    dispatch_queue_t queue = dispatch_queue_create("NSConditionLock", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 10; i++) {
        dispatch_async(queue, ^{
            
            [weakSelf testNSConditionAdd];
        });
    }
    for (int i = 0; i < 10; i++) {
        dispatch_async(queue, ^{
            
            [weakSelf testNSConditionRemove];
        });
    }
}
//生产
- (void)testNSConditionAdd
{
    [_lock lock];
    NSObject *object = [NSObject new];
    [self.array addObject:object];
    NSLog(@"--->>%@ add", [NSThread currentThread]);
    [_lock signal];
    [_lock unlock];
    NSLog(@"--->>%lu add", (unsigned long)self.array.count);
}

//消费
- (void)testNSConditionRemove
{
    [_lock lock];
    if (_array.count == 0) {
        
        NSLog(@"--->> wait");
        [_lock wait];
    }
    [self.array removeObjectAtIndex:0];
    NSLog(@"--->>%@ remove", [NSThread currentThread]);
    [_lock unlock];
    NSLog(@"--->>%lu remove", (unsigned long)self.array.count);
}

5.dispatch_semaphore

信号量主要有3个函数,分别是:

//创建信号量,参数:信号量的初值,如果小于0则会返回NULL
dispatch_semaphore_create(信号量值)

//等待降低信号量
dispatch_semaphore_wait(信号量,等待时间)

//提高信号量
dispatch_semaphore_signal(信号量)

注意:正常的使用顺序是先降低然后提高,这两个函数通常都是成对出现。

@property (nonatomic ,strong)dispatch_semaphore_t semaphore;
@property (nonatomic ,assign)NSInteger numCount;

typeof(self) __weak weakSelf = self;
_semaphore = dispatch_semaphore_create(1);//这里的”1“指的是同一时间内执行的线程数不超过1;
_numCount = 100;//总票数
dispatch_queue_t queue = dispatch_queue_create("semaphoreLock", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 2; i++) {
        dispatch_async(queue, ^{
            [weakSelf testtestDispatchSemaphore:i];
        });
    }

- (void)testtestDispatchSemaphore:(NSInteger)num
{
    while (1) {
        long ret = dispatch_semaphore_wait(_semaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.21*NSEC_PER_SEC)));
        NSLog(@"-------------------%ld",ret);
        if (ret == 0) {
            if (_numCount > 0) {
                NSLog(@"%d 窗口 卖了第%d张票", (int)num, (int)_numCount);
                _numCount --;
            }else{
                dispatch_semaphore_signal(_semaphore);
                NSLog(@"卖光了");
                break;
            }
            sleep(0.2);
            dispatch_semaphore_signal(_semaphore);
        }else{
            NSLog(@"%d %@", (int)num, @"超时了");
        }
        sleep(0.2);
    }
}

本文主要参考了这篇文章(https://www.cnblogs.com/crash-wu/p/4806499.html
),并对其中所能理解的部分进行一一验证,以前没怎么写过类似的简书,如果有什么做的不好的地方还请大家多多见谅!

上一篇 下一篇

猜你喜欢

热点阅读