一、线程 进程
* 一个程序就是一个进程,一个程序的多个任务被称为线程。
* 进程是表示资源分配的基本单元,线程是进程中执行和调度的基本单元。
* 资源分配给进程,同一个进程可以有多个线程,同一个进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储),但是每个线程拥有自己的栈段,栈段又叫做运行时段,用来存储所有的临时变量和局部变量。
* 处理机分配给线程,即真正运行的是线程。线程执行过程中,需要协作同步,不同的进程的线程利用消息通信的方法进行同步。
//最常用的消息通信是 基于 performSelector dispatch_async MachPort 进行主线程和子线程的通信 。
//关于MachPort的细节可以结合runloop再进行讨论。
二、多线程
* 同一时间,CPU只能处理1条线程,多线程并发执行,其实是CPU快速的在多条线程之间进行调度。
* 开启线程需要一定的内存空间,主线程占用1M,子线程占用512KB,如果线程特别多,会占用大量的内存空间,降低程序的性能。
三、任务和队列
队列:这里的队列指执行任务的等待队列,是一种特殊的线形表,采用 FIFO原则。
任务 :执行操作的意思,就是线程中执行的那段代码。
队列包含 :串行队列(包含主队列)、并行队列
任务执行方式 :同步执行、异步执行
组合:
* 串行队列、同步执行 不开启新线程,任务依次执行
* 串行队列、异步执行 开启一个新线程,任务依次执行
* 并行队列、同步执行 不开启新线程,任务依次执行
* 并行队列、异步执行 开启多个新线程,任务并发执行
四、iOS中的多线程
主要有三种,NSThread、NSoperationQueue,GCD
1.NSThread 轻量级别的多线程技术
基本语法
片段1
NSThread *th = [[NSThread alloc] initWithTarget:self selector:@selector(test:) object:@"123"];
th.threadPriority = 1;
th.name = @"new";
[th start];
[th cancel];
[NSThread detachNewThreadSelector:@selector(testThread:) toTarget:self withObject:@"123"];
片段2
- 当前线程 1秒后执行
[self performSelector:@selector(aaa) withObject:nil afterDelay:1]; - 回到主线程
[self perfomSelectorOnMainThread:@selector(aaa) withObject:nil waitUntilDone:YES];
*开辟子线程
[self perfomSelectorInBackground:@selector(aaa) withObject:nil];
*在指定线程执行
[self performSelector:@selector(aaa) onThread:[NSThread currentThread] withObject:nil waitUntilDone:YES];
* 构建方式:初始化方式、构造器方式
* 如果是初始化方式,需要自己启动(start)和资源销毁(cancel),threadPriority 0~1。
* 如果是构造器方式,会自动启动。
* performSelector NSObject的子类或者对象都可以调用此方法,
* waitUntilDone:YES 如果设置为YES就必须等回调方法执行完毕后再执行后面的代码
* afterDelay 会在内部创建一个NSTimer,然后加到当前线程runloop中,如果没有开启runloop,该方法会失效,也就是在子线程中,需要启动runloop。
2.GCD 对比 NSOpreationQueue
1、两者之间的关系
GCD是面向底层C语言的API,NSOprationQueue用GCD封装构建的,是 GCD的高级抽象。
2、两者之间的区别
- GCD执行效率更高,写起来也更方便
- GCD只支持FIFO的队列,而NSOprationQueue可以设置最大并发数,优先级、依赖等调整执行顺序。
- NSOprationQueue是面向对象的,所以支持KVO,可以检测operation状态,如正在执行(isExecuted)、是否结束(isFinished)、是否取消(isCanceld)
3、两者之间的选择 - 实际的项目开发中,很多时候会用用到异步操作,不会有特别复杂的关系管理,所以苹果推崇完善和运行快速的GCD
- 如果考虑操作之间的事物性,顺序性,依赖关系等,如多线程并发下载,GCD需要自己写更多的代码实现,而NSOpreationQueue已经内建了这些支持。
五、死锁
在串行队列的任务中,执行同步任务,因为串行队列需要等待任务执行结束才能执行下一个任务,所以会造成死锁。
六、栅栏函数 dispatch_barrier_async
使用范例:可以做到多读单写,在写操作中加入barrier。
dispatch_barrier_async和dispatch_barrier_sync 特点
1、两者同样是干预了本队列中任务的执行,都是先执行前面的任务再执行后面的任务。
2、两者之间唯一的区别是,前者不会干预任务的插入,后者必须等待前面的任务执行结束以后才会对后面的任务进行插入。
七、Dispatch Semaphore 信号量
GCD中的信号量是指 Dispatch Semaphore,是持有计数的信号。
提供了三个函数
dispatch_semaphore_create 创建并初始化总量
dispatch_semaphore_signal 发送信号,总量+1
dispatch_semaphore_wait 总量-1,如果总量为0会一直等待。
主要作用:
1同步
2加锁 实现步骤:初始化信号量为1,执行代码段先wait锁住,代码末尾signal放开。
八、延时函数dispatch_after
使用的是dispatch_time_t , 不用考虑runloop是否开启
九、自旋锁和互斥锁
区别:
* 自旋锁会忙等,即在访问被锁资源时,调用者线程不会休眠,而是在不停的循环在那里,知道被锁资源释放锁。
* 互斥锁会休眠,即在访问被锁资源时,调用者会休眠,此时cpu可以调度其他线程工作,知道被锁资源释放锁,此时会唤醒休眠线程。
*自旋锁高效但是消耗cpu,可以在耗时较少的时候使用。
*自旋锁:atomic,OSSpinLock,dispatch_semaphore_t
互斥锁:pthread_mutex,@synchronized,NSLock,NSConditionLock,NSCondition,NSRecursiveLock(递归锁)
网友评论