iOS多线程编程及GCD简介

陆宇航
2023-12-01

程序APP进程、线程、多线程

1.程序是计算机(电脑,智能手机,机器人等有操作系统的智能新生物)指令的集合,以文件形式存储在磁盘上。
2.进程是一个正在运行的程序实例,是一个程序在其自身的地址空间中的一次执行活动。
3.进程由内核对象和地址空间组成。
4.线程由内核对象和线程栈组成,它是进程运行过程中的某个时间片,多核CUP时,线程就实现了同时运行。

iOS提供四种多线程编程技术

NSThread

NSThread相对其他几个比较轻量级。
需要自己管理线程的生命周期,线程同步。
线程同步对数据的加锁会有一定的系统开销。

Cocoa NSOperation

是对GCD的封装,不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作任务上。可以轻松调用cancelOperation取消操作任务。
相关类NSOperation,NSOperationQueue。
NSOperation是个抽象类,使用它必须用它的子类,可以自定义子类或用Cocoa定义好的两个子类NSInvocationOperation, NSBlockOperation.
创建NSOperation子类的对象,把对象添加到NSOperationQueue队列里执行。

pthread

pthread是一套通用的多线程API,适用于Linux、windows、Unix跨平台,可移植,使用C语言,生命周期需要程序员管理,iOS开发中使用很少。

GCD

Grand Central Dispatch是iOS4.0开始后,Apple开发的一个多核编程的解决方案。
GCD确实好用,很强大,是替代其他多线程编程很高效强大的技术。相比NSOperation,GCD无法轻松取消任务(可以取消)。用不好可能出现线程死锁。如

- (void)viewDidLoad{
    [super viewDidLoad];
    NSLog(@"=================4");
    dispatch_sync(dispatch_get_main_queue(),^{ 
		   NSLog(@"=================5"); 
    });
    NSLog(@"=================6");
}

应改为

- (void)viewDidLoad{
    [super viewDidLoad];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"=================1");
	    dispatch_sync(dispatch_get_main_queue(), ^{
	        NSLog(@"=================2"); 
        });
        NSLog(@"=================3");
    });
}

GCD多线程的管理

  • 开不开线程,取决于执行任务的函数,同步不开,异步才能开
  • 开几条线程,取决于队列,串行开一条,并发可以开多条(异步)

串行队列Serial Dispatch Queue

队列中的任务只会顺序执行,主队列是系统自带的串行队列。
要避免多线程更新相同资源导致数据竞争时,用串行队列.

dispatch_queue_t q = dispatch_queue_create("nameOfQueue",dispatch_queue_serial);

并行队列Concurrent Dispatch Queue

队列中的任务通常会并发执行,全局队列是系统提供的并行队列。

dispatch_queue_t q = dispatch_queue_create("nameOfQueue",dispatch_queue_concurrent);

全局队列

是系统提供的,直接拿过来用就可以;与并行队列类似,但是调试时,无法确认操作所在队列。

dispatch_queue_t q = dispatch_global_queue_create(DISPATCH_QUEUE_PRIORITY_DAFAULT,0);

主队列

每一个应用开发程序对应唯一一个主队列,直接get即可,在多线程开发中,使用主队列更新UI。

dispatch_queue_t q = dispatch_get_main_queue(DISPATCH_QUEUE_PRIORITY_DAFAULT,0);

等待GCD任务

GCD实现1,2并行和3串行和4,5串行,4,5是并行。3延时3秒执行。

- (void)mutiThreadWork{
  //并行执行1,2
  dispatch_group_t group  = dispatch_group_create();
  dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
    NSLog(@"1");
  });
  dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"2");
  });
  //1,2处理晚后,延时执行3
  dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        
        dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull*NSEC_PER_SEC);
        dispatch_after(time , dispatch_get_global_queue(0, 0), ^{
            NSLog(@"3");
            //4,5串行
            dispatch_async(group, dispatch_get_main_queue(), ^{
                sleep(10);
                NSLog(@"4");
            });
            dispatch_async(group, dispatch_get_main_queue(), ^{
                sleep(5);
                NSLog(@"5");
            });
        });
    });
}

详细参阅:
GCD实现异步线程的等待实行

取消GCD任务

请参阅:
https://www.cnblogs.com/beckwang0912/p/7136862.html

GCD实现信号量管理

请参阅:
http://blog.csdn.net/huifeidexin_1/article/details/9494975
http://blog.csdn.net/yongyinmg/article/details/38065255

GCD死锁

请参阅:
iOS 开发微信公众号博文
总结一句话:除非串行队列(包含主队列)的外层有不同队列的异步线程,否则串行队列的同步线程造成死锁。

GCD使用应该注意的

  • 串行队列开启异步任务,是有执行顺序的。
  • 并行队列里开启同步任务是有执行顺序的,只有异步任务才没有顺序。
  • 主队列是GCD自带的串行队列,会在主线程中顺序执行。全局队列开启异步任务,并发执行(顺序不定)。
  • 在同一串行队列开启异步任务后嵌套同步任务(修改UI或其他)造成死锁。
  • 更多内容请参阅《Objective-C高级编程——iOS与OS X多线程和内存管理》
 类似资料: