一.线程与进程
进程与线程的理解:
- CPU(工厂)—进程(车间)—-线程(工人):如下图
进程与线程的资源共享:
车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征 一个进程的内存空间是共享的,每个线程都可以使用这些共享内存.
加锁机制(控制资源管理):
- 可是,每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面 有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线 程必须等它结束,才能使用这一块内存
- 一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人 看到上锁,就在门口排队,等锁打开再进去。这就叫“互斥锁”(Mutual exclusion, 缩写 Mutex),防止多个线程同时读写某一块内存区域.
信号量: - 还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出 来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用.
- 这时的解决方法,就是在门口挂n把钥匙。进去的人就取一把钥匙,出来时再把钥 匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。这种做法叫 做”信号量”(Semaphore),用来保证多个线程不会互相冲突。
不难看出,mutex是semaphore的一种特殊情况(n=1时)。也就是说,完全可 以用后者替代前者。但是,因为mutex较为简单,且效率高,所以在必须保证资源独 占的情况下,还是采用这种设计。
操作系统的设计,因此可以归结为三点:
- (1)以多进程形式,允许多个任务同时运行;
- (2)以多线程形式,允许单个任务分成不同的部分运行;
(3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之 间和线程之间共享资源
进程与线程的区别:
- 进程是指在系统中正在运行的一个应用程序,都有独立的内存空间,一般来说一个应 用程序存在一个进程,但也多个进程的情况
- 同一个进程中的线程共享内存和资源
二.线程生命周期
CPU的使用权:
线程(thread)
- 程序执行的最小单元,按照线性顺序执行的一个流程,CPU的调度单位,一核同时只
能执行一个线程
多线程
- 一个应用程序有多个线程,多线程不是为了提高运行效率,而是为了提高资源使用效 率来提高系统的效率
- 一个程序有且只有一个主线程,程序启动时创建(调用main来启动)主线程的生命周 期是和应用程序绑定的,程序退出(结束)时,主线程也就停止了
任何有可能堵塞主线程的任务不要在主线程执行(比如访问网络)
单线程与多线程的执行图:
线程的生命周期:
- 新建状态(New):新创建了 一个线程对象
就绪状态(Runnable):线 程对象创建后,其他线程调用 了该对象的start()方法,该状 态的线程位于可运行线程池中, 变得可运行,等待获取CPU 的使用权
运行状态(Running):就绪状态的线程获取了CPU ,执行程序代码
阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行 ,直到线程进入就绪状态,才有机会转到运行状态
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期
三.线程调度
线程的使用:
线程实现
- NSTread
优点:NSTread比其他两个轻量级
缺点:需要自己管理线程的生命周期,线程同步,加锁等 - Cocoa operation
优点:不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上
Cocoa operation相关的类是NSOpration,NSOperationQuque.
NSOperationQuque是操作队列,用来管理和控制NSOpration.NSOpration是操作任务,是抽象类,使用它必须用它的类. - GCD(Grand Central Dispatch)
- GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的
一个高效、强大、底层的技术。
- GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的
线程的使用,代码实现:
NSThread的创建
#import "ViewController.h"
#import "CustomThread.h"
@interface ViewController ()
@end
@implementation ViewController
/*
1 NSThread 常用的类 属性 方法
2 case1~case4
3 退出 取消
*/
- (void)viewDidLoad {
[super viewDidLoad];
//case1
NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(threadCallMethod) object:nil];
//启动线程,调用start方法
[thread1 start];
//线程的退出 (只是退出后面还没有来得及执行的线程)
// [NSThread exit];
//指定线程退出
//(1)先标记thread1的状态是cancel
[self performSelector:@selector(cancelThread1:) withObject:thread1 afterDelay:1];
//case2 (没有返回值 不需要调用start方法)
// [NSThread detachNewThreadSelector:@selector(threadCallMethod) toTarget:self withObject:nil];
//case3
// [self performSelectorInBackground:@selector(threadCallMethod) withObject:nil];
// [self performSelectorOnMainThread:<#(nonnull SEL)#> withObject:<#(nullable id)#> waitUntilDone:<#(BOOL)#>]
//case4 自定义线程
// CustomThread *thread4 = [[CustomThread alloc]init];
//启动方法
//直接调用main方法,只是调用了一个普通的方法
// [thread4 main];
//启动线程 新的线程会执行相应线程汇总的main方法,并且会开辟一个新的线程
// [thread4 start];
NSLog(@"ViewController的优先级:%lf",[NSThread threadPriority]);
NSLog(@"ViewController是否是主线程:%d",[[NSThread currentThread] isMainThread]);
}
-(void)cancelThread1:(NSThread*)thread{
[thread cancel];
}
-(void)threadCallMethod{
//(2)延迟2s,判断当前线程是否是被取消的状态.
[NSThread sleepForTimeInterval:2];
if ([[NSThread currentThread]isCancelled]) {
//如果是,退出线程
[NSThread exit];
}
NSLog(@"threadPriority的优先级:%lf",[NSThread threadPriority]);
NSLog(@"threadCallMethod是否是主线程:%d",[[NSThread currentThread] isMainThread]);
}
@end
import “CustomThread.h”
@implementation CustomThread
-(void)test{
}
-(void)main{
NSLog(@"threadPriority的优先级:%lf",[NSThread threadPriority]);
NSLog(@"threadCallMethod是否是主线程:%d",[[NSThread currentThread] isMainThread]);
}
NSOperation的创建
import “ViewController.h”
import “CustomOperation.h”
@interface ViewController ()
{
NSInvocationOperation *cancelOperation;
}
@end
@implementation ViewController
(void)viewDidLoad {
[super viewDidLoad];//初始化任务队列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];//设置队列的最大并发数
queue.maxConcurrentOperationCount = 1;//queue 被挂起(暂停)
queue.suspended = YES;//添加任务
//case 1
[queue addOperationWithBlock:^{NSLog(@"operation1"); //队列中的任务是在子线程中执行的.
// NSLog(@”%d”,[[NSThread currentThread]isMainThread]);
}];
//case 2
//NSBlockOperation:能够并发的执行一个或者多个任务
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{for (int i =0; i<10; i++) { NSLog(@"operation2----%d",i); }
}];
//添加任务 和blockOperation的第一任务并发执行
[blockOperation addExecutionBlock:^{NSLog(@"又执行了一个新的操作:线程:%@",[NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{NSLog(@"又执行了一个新的操作:线程:%@",[NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{NSLog(@"又执行了一个新的操作:线程:%@",[NSThread currentThread]);
}];
//监听blockOperation中的任务完成后,调用该block
blockOperation.completionBlock=^(){NSLog(@"blockOperation的任务都完成了");
};
//将operation添加到queue
[queue addOperation:blockOperation];//case 3
NSInvocationOperation *invocationOp =[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(threadCallMethod) object:nil];
[queue addOperation:invocationOp];//case 4 自定义operation
CustomOperation *cusOp = [[CustomOperation alloc]init];//设置当前opration在queue中的优先级,优先级越大,越先执行.
[cusOp setQueuePriority:NSOperationQueuePriorityVeryHigh];//addDependency:添加依赖关系(改变执行的顺序)
//blockOperation依赖于invocationOp
//必须等到invocationOp执行完毕后才可以执行blockOperation
[blockOperation addDependency:invocationOp];[queue addOperation:cusOp];
//取消任务
cancelOperation = [[NSInvocationOperation alloc]initWithTarget:self selector: @selector(cancelOperationTask) object:nil];[queue addOperation:cancelOperation];
//取消单个任务
//(1)先将operation标记成cancel状态
//(2)在任务执行的时候判断是否是cancel状态
// [self performSelector:@selector(cancelSingelOperation:) withObject:cancelOperation afterDelay:1];
//取消所有任务
[self performSelector:@selector(cancelallOperation:) withObject:queue afterDelay:1];
//关闭暂停
queue.suspended = NO;
}
-(void)cancelallOperation:(NSOperationQueue*)q{
//如果一个操作已经在执行,不会停止.
//队列取消所有的任务
[q cancelAllOperations];
}
-(void)cancelSingelOperation:(NSInvocationOperation*)op{
[op cancel];
}
-(void)cancelOperationTask{
[NSThread sleepForTimeInterval:2];
if (cancelOperation.isCancelled) {
NSLog(@"cancelOperation is cancelled");
}else{
NSLog(@"cancelOperation is executing");
}
}
-(void)threadCallMethod{
for (int i =0; i<10; i++) {
NSLog(@"operation3----%d",i);
}
}
@end
import “CustomOperation.h”
@implementation CustomOperation
-(void)main{
for (int i =0; i<10; i++) {
NSLog(@"operation4----%d",i);
}
}
@end
“`
四 .同步,异步,阻塞,非阻塞
名词解释:
- 队列:是先进先出(FIFO, First-In-First-Out)的线性表。通常用链表或者数组来实 现。队列只允许在后端(称为rear)进行插入操作,在前端(称为front)进行删除操作
任务:具体要做的东西,比如方法调用等
串行 xing(serial):使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度,指我们做任务时,一个一个步骤去执行
并发(Concurrent):一个处理器同时处理多个任务。并发事件之间不一定要同一 时刻发生,指逻辑上的同时发生
并行( parallel):多个处理器或多核处理器同时处理多个不同的任务。同时发生的 两个并发事件,具有并发的含义,而并发则不一定并行,指物理上的同时发生。
同步:调用者调用一个任务开始执行后,调用者得等待 拿到了结果 才会继续往下执 行
异步:调用者调用一个任务开始执行后,调用者不用等待 拿到结果,会继续往下执行。 实际上任务执行完成后会通知调用者
阻塞:指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回
非阻塞:指不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回
死锁:是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而 造成的一种阻塞的现象
互斥锁:多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读 写的机制
信号量:又称为信号灯,是一个计数器,它用来记录对某个资源(如共享内存)的存 取状况