iOS基础·OC高级篇iOS

iOS知识复习笔记(1)---多线程

2023-01-09  本文已影响0人  焦下客

Q. iOS开发中有多少类型的线程?分别对比

  1. Pthreads // 跨系统c语言多线程框架,不推荐。
  2. NSTread // 面向对象,需要手动管理生命周期
  3. GCD :Grand Central Dispatch // 主打任务与队列,告诉他要做什么即可。
  4. NSOperation & NSOperationQueue // GCD 的封装,面向对象。

Q.GCD和NSOperationQueue对比

GCD是面向底层的C语言API,NSOperationQueue用GCD构建封装的,是GCD的高级抽血。

  1. GCD执行效率更高,而且由于队列中执行的是由block构成的任务,这是一个轻量级别的数据结构,写起来更方便。
  2. GCD只支持FIFO的队列,而NSOperationQueue可以用过设置最大并发数,设置优先级,添加依赖关系等调整执行顺序。
  3. NSOperationQueue甚至可以跨队列设置依赖关系,但是GCD只能通过设置串行队列,或者在队列内添加barrier(dispatch_barrier_async)任务,才能控制执行顺序,较为复杂。
  4. NSOperationQueue因为面向对象,所以支持KVO,可以监测operation是否在执行(isExecuted)、是否结束(isFinished)、是否取消(isCanceld)

Q.如何实现同步,有多少说多少

  1. Disaptch_async (在同一个串行队列)
  2. Dispatch_sync()
  3. Dispatch_barrier_sync()
  4. Dispatch_group_create() + dispatch_group_wait()
  5. Dispatch_apply(1,...)
  6. NSOperationQueue.maxConcurrentOperationCount = 1
  7. os_unfair_lock
  8. Pthread_mutex 互斥锁
  9. @synchronied
  10. NSLock
  11. NSRecursiveLock 递归锁
  12. NSConditionLock & NSCondition 条件锁
  13. Dispatch_semaphore_create() + dispatch_semaphore_wait()

Q.dispath_once实现原理

1.读取token值 dispatch_once_t.dgo_once

2.若Block已完成,return

3.若block没有完成,尝试原子性修改dispatch_once_t.dgo_once 值为 DLOCK_ONCE_UNLOCKED

4.修改成功,执行block,原子性修改 dispatch_once_t.dgo_once 为 DLOCK_ONCE_DONE

5.若失败,则进入循环等待。

Q.什么情况下会死锁

  1. 单线程

    对正在执行任务的串行队列添加同步任务

    /// 在主线程中执行这句代码
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"这里死锁了");
    });
    
    
    /// 在哪里执行都可以
    dispatch_queue_t theSerialQueue = dispatch_queue_create("我是个串行队列", DISPATCH_QUEUE_SERIAL);
    dispatch_async(theSerialQueue, ^{ /// 正在执行任务,同步异步无所谓
        NSLog(@"第一层");
        
        /// 同一个串行队列
        dispatch_sync(theSerialQueue, ^{
            NSLog(@"第二层");
            
        });
    });
    
    
  1. 多线程

简单来说,A等B,同时B等A。

例如某个任务需要多个资源,比如资源1、资源2。此时,线程A和线程B都要执行这个任务。但是,线程A先抢占了资源1,同时线程B抢占了资源2。这个时候,线程A还需要资源2才能执行任务;同样的,线程B需要资源1才能执行任务。于是,A等B,B等A,死锁来了。

- (void)deadLock {
    
    
    NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(deadLock1) object:nil];
    [thread1 setName:@"【线程 汤姆】"];
    
    NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(deadLock2) object:nil];
    [thread2 setName:@"【线程 杰瑞】"];
    
    [thread1 start];
    [thread2 start];
}

- (void)deadLock1 {
    
    [self.lock1 lock];
    NSLog(@"%@ 锁住 lock1", [NSThread currentThread]);
    
    // 线程休眠一秒
    [NSThread sleepForTimeInterval:1];
    
    [self.lock2 lock];
    NSLog(@"%@ 锁住 lock2", [NSThread currentThread]);

    
    [self doSomething];
    
    
    [self.lock2 unlock];
    NSLog(@"%@ 解锁 lock2", [NSThread currentThread]);
    
    [self.lock1 unlock];
    NSLog(@"%@ 解锁 lock1", [NSThread currentThread]);
}


- (void)deadLock2 {
    
    [self.lock2 lock];
    NSLog(@"%@ 锁住 lock2", [NSThread currentThread]);
    
    // 线程休眠一秒
    [NSThread sleepForTimeInterval:1];
    
    [self.lock1 lock];
    NSLog(@"%@ 锁住 lock1", [NSThread currentThread]);
    
    
    [self doSomething];
    
    
    [self.lock1 unlock];
    NSLog(@"%@ 解锁 lock1", [NSThread currentThread]);
    
    [self.lock2 unlock];
    NSLog(@"%@ 解锁 lock2", [NSThread currentThread]);
}

上一篇下一篇

猜你喜欢

热点阅读