iOS学习

iOS-底层原理22-多线程

2021-01-21  本文已影响0人  一亩三分甜

《iOS底层原理文章汇总》

1.进程和线程

地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间。 资源拥有:同一进程内的线程共享本进程的资源如内存、I/O、cpu等,但是进程之间的 资源是独立的。

1: 一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进 程都死掉。所以多进程要比多线程健壮。
2: 进程切换时,消耗的资源大,效率高。所以涉及到频繁的切换时,使用线程要好于进 程。同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程 3: 执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口。但是 线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
4: 线程是处理器调度的基本单位,但是进程不是。 5: 线程没有地址空间,线程包含在进程地址空间中

/**
     pthread_create 创建线程
     参数:
     1. pthread_t:要创建线程的结构体指针,通常开发的时候,如果遇到 C 语言的结构体,类型后缀 `_t / Ref` 结尾
     同时不需要 `*`
     2. 线程的属性,nil(空对象 - OC 使用的) / NULL(空地址,0 C 使用的)
     3. 线程要执行的`函数地址`
     void *: 返回类型,表示指向任意对象的指针,和 OC 中的 id 类似
     (*): 函数名
     (void *): 参数类型,void *
     4. 传递给第三个参数(函数)的`参数`
     
     返回值:C 语言框架中非常常见
     int
     0          创建线程成功!成功只有一种可能
     非 0       创建线程失败的错误码,失败有多种可能!
     */
    
    // 1: pthread
    pthread_t threadId = NULL;
    //c字符串
    char *cString = "HelloCode";
//    NSString *ocString = @"Gavin";
    //延伸到: OC--C的混编 尤其在智能家居,SDK封装
    //抛出一个问题: 在ARC需要这样操作,在MRC不需要
    // OC prethread -- 跨平台
    // 锁
    int result = pthread_create(&threadId, NULL, pthreadTest, cString);
    if (result == 0) {
        NSLog(@"成功");
    } else {
        NSLog(@"失败");
    }
    // 2: NSThread
    [NSThread detachNewThreadSelector:@selector(threadTest) toTarget:self withObject:nil];
    // 3: GCD
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [self threadTest];
    });
    
    // 4: NSOperation
    [[[NSOperationQueue alloc] init] addOperationWithBlock:^{
        [self threadTest];
    }];
    
/**
 1. 循环的执行速度很快
 2. 栈区/常量区的内存操作也挺快
 3. 堆区的内存操作有点慢
 4. I(Input输入) / O(Output 输出) 操作的速度是最慢的!
 * 会严重的造成界面的卡顿,影响用户体验!
 * 多线程:开启一条线程,将耗时的操作放在新的线程中执行
 */
- (void)threadTest{
    NSLog(@"begin");
    NSInteger count = 1000 * 100;
    for (NSInteger i = 0; i < count; i++) {
        // 栈区
        NSInteger num = i;
        // 常量区
        NSString *name = @"zhang";
        // 堆区
        NSString *myName = [NSString stringWithFormat:@"%@ - %zd", name, num];
        NSLog(@"%@", myName);
    }
    NSLog(@"over");
}

void *pthreadTest(void *para){
    // 接 C 语言的字符串
    //    NSLog(@"===> %@ %s", [NSThread currentThread], para);
    // __bridge 将 C 语言的类型桥接到 OC 的类型
    NSString *name = (__bridge NSString *)(para);
    
    NSLog(@"===>%@ %@", [NSThread currentThread], name);
    
    return NULL;
}

单核CPU,在内存中的多线程是快速切换,用户无法感知到切换


image.png

时间片的概念:CPU在多个任务直接进行快速的切换,这个时间间隔就是时间片

2.线程属性,命名name

image.png

3.线程生命周期

image.png

线程池


image.png

饱和策略


image.png
image.png
线程中的所有任务都能cancel掉吗?正在执行的任务无法cancel,正在执行的任务已经被调度上去了
image.png

4.threadPriority优先级qualityOfService,优先级越高表明执行速度越快,还与任务的复杂度有关

5.多任务在一条线程,会有资源抢夺的问题

6.线程间通讯

- (void)viewDidLoad {
    [super viewDidLoad];

    _imageView = [[UIImageView alloc] init];
    
    // 1. 准备 URL
    NSString *urlString = @"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1529488045873&di=7c1cc40bec638406ef48717386a08094&imgtype=0&src=http%3A%2F%2Fpic2.ooopic.com%2F12%2F46%2F41%2F95bOOOPIC74_1024.jpg";
    NSURL *url = [NSURL URLWithString:urlString];

    // 2. 下载图像
    //[self downloadImageWithURL:url];
    // 异步下载图像
    [self performSelectorInBackground:@selector(downloadImageWithURL:) withObject:url];

}

/**
 * 下载 URL 指定的网络图片
 */
- (void)downloadImageWithURL:(NSURL *)url {
    
    NSLog(@"%@", [NSThread currentThread]);
    
    // 1. 所有从网络返回的都是二进制数据
    NSData *data = [NSData dataWithContentsOfURL:url];
    
    // 2. 将二进制数据转换成 image
    UIImage *image = [UIImage imageWithData:data];
    
    // 3. 在主线程更新 UI
    // waitUntilDone: 是否等待 updateImage: 执行完成
    [self performSelectorOnMainThread:@selector(updateImage:) withObject:image waitUntilDone:YES];
    
    NSLog(@"完成");
}
/**
 * 更新图像 UI
 */
- (void)updateImage:(UIImage *)image {
    
    NSLog(@"更新 UI -> %@", [NSThread currentThread]);
    
    // 3. 设置图像
    _imageView.image = image;
    
    // 4. 调整大小
    [_imageView sizeToFit];
    
    // 5. 设置 contentSize
    _scrollView.contentSize = image.size;
}

7.端口间通信

把port加入runloop,[[NSRunLoop currentRunLoop] addPort:self.myPort forMode:NSDefaultRunLoopMode],接收port消息的端口加入runloop里面


image.png
image.png

8.UIImageView用weak修饰

weak修饰ImageView,一创建就释放了,栈区的空间系统自动管理回收,无法进行添加,可以通过添加中间变量进行赋值,引用计数进行传递,在函数viewDidLoad中都不会被销毁


image.png
image.png
上一篇 下一篇

猜你喜欢

热点阅读