美文网首页
iOS高级进阶之多线程 (二)

iOS高级进阶之多线程 (二)

作者: iOS刘耀宗 | 来源:发表于2021-05-28 11:37 被阅读0次

    关注我,连载进行中....
    什么情况会产生死锁! 下面这句话总结
    使用 sync 函数往当前串行队列添加任务就会卡住当前的串行队列(产生死锁)
    队列组的使用

        // 创建队列组
        dispatch_group_t group = dispatch_group_create();
        // 创建并发队列
        dispatch_queue_t queue = dispatch_queue_create("my_queue", DISPATCH_QUEUE_CONCURRENT);
        
        // 添加异步任务
        dispatch_group_async(group, queue, ^{
            for (int i = 0; i < 5; i++) {
                NSLog(@"任务1-%@", [NSThread currentThread]);
            }
        });
        
        dispatch_group_async(group, queue, ^{
            for (int i = 0; i < 5; i++) {
                NSLog(@"任务2-%@", [NSThread currentThread]);
            }
        });
        
    //     等前面的任务执行完毕后,会自动执行这个任务
        dispatch_group_notify(group, queue, ^{
            dispatch_async(dispatch_get_main_queue(), ^{
                for (int i = 0; i < 5; i++) {
                    NSLog(@"任务3-%@", [NSThread currentThread]);
                }
            });
        });
    

    多线程的隐患
    1: 1 块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源
    2: 比如多个线程访问同一个对象,同一个变量,同一个文件
    3:当多个线程访问同一块资源的时候,很容易引发数据错乱和数据安全问题

    多线程安全隐患示例01 – 存钱取钱

    图片.png

    多线程安全隐患示例02 – 卖票


    图片.png

    上面是两个比较有代表性的多线程安全隐患示例:
    大致解释一下. 比入存钱取钱. 1000 元是余额. 开启两条线程异步执行

    开启一条线程,余额 1000, 存 1000 进去,然后对余额进行操作之后 然后余额是 2000
    开启另外一条线程.余额: 1000. 取出 500 然后对余额进行操作之后是 500
    本来最终的结果应该是 1000. 但是由于多线程的问题,就会导致 500 和 2000 的出现.

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        [self moneyTest];
    }
    
    /**
     存钱、取钱演示
     */
    - (void)moneyTest
    {
        self.money = 100;
        
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        
        dispatch_async(queue, ^{
            for (int i = 0; i < 10; i++) {
                [self saveMoney];
            }
        });
        
        dispatch_async(queue, ^{
            for (int i = 0; i < 10; i++) {
                [self drawMoney];
            }
        });
    }
    
    /**
     存钱
     */
    - (void)saveMoney
    {
        int oldMoney = self.money;
        sleep(.2);
        oldMoney += 50;
        self.money = oldMoney;
        
        NSLog(@"存50,还剩%d元 - %@", oldMoney, [NSThread currentThread]);
    }
    
    /**
     取钱
     */
    - (void)drawMoney
    {
        int oldMoney = self.money;
        sleep(.2);
        oldMoney -= 20;
        self.money = oldMoney;
        
        NSLog(@"取20,还剩%d元 - %@", oldMoney, [NSThread currentThread]);
    }
    
    /**
     卖1张票
     */
    - (void)saleTicket
    {
        int oldTicketsCount = self.ticketsCount;
        sleep(.2);
        oldTicketsCount--;
        self.ticketsCount = oldTicketsCount;
        
        NSLog(@"还剩%d张票 - %@", oldTicketsCount, [NSThread currentThread]);
    }
    
    /**
     卖票演示
     */
    - (void)ticketTest
    {
        self.ticketsCount = 15;
        
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        
        dispatch_async(queue, ^{
            for (int i = 0; i < 5; i++) {
                 [self saleTicket];
            }
        });
        
        dispatch_async(queue, ^{
            for (int i = 0; i < 5; i++) {
                [self saleTicket];
            }
        });
        
        dispatch_async(queue, ^{
            for (int i = 0; i < 5; i++) {
                [self saleTicket];
            }
        });
    }
    
    存钱取钱.png
    售票.png

    怎么处理多线程问题
    加锁
    下面是一些常见的方案:
    OSSpinLock
    os_unfair_lock
    pthread_mutex
    dispatch_semaphore
    dispatch_queue(DISPATCH_QUEUE_SERIAL)
    NSLock
    NSRecursiveLock
    NSCondition
    NSConditionLock
    @synchronized

    OSSpinLock叫做”自旋锁”,等待锁的线程会处于忙等(busy-wait)状态,一直占用着CPU资源
    目前已经不再安全,可能会出现优先级反转问题
    如果等待锁的线程优先级较高,它会一直占用着CPU资源,优先级低的线程就无法释放锁
    需要导入头文件#import <libkern/OSAtomic.h>

    相关文章

      网友评论

          本文标题:iOS高级进阶之多线程 (二)

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