总结:
1.进程和线程
进程是系统中正在运行的一个应用程序,活动监视器可以看到。
线程是CPU执行任务的最小单元。
进程是CPU分配资源的最小单元。
一个应用程序运行至少有一个进程,一个进程中至少有一个主线程。
2.iOS 中的线程 应用
pthread NSThread GCD NSOpreation
1.pthread:
pthread_create(&threadId, NULL, &demo, (__bridge void *)(str));
2.NSThread- 写常驻线程。
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"jack"];
[self performSelectorInBackground:@selector(run:) withObject:@"jack"];
2.1
NSThread start()方法源码里面会启动一个nsthreadLauncher方法
[t main];
[NSThread exit];
- (void) main
{
略。。。
[_target performSelector: _selector withObject: _arg];
}
所以要把常驻线程写在selector里面,子线程的runloop 默认是停止的。
2.2sched_yield :sched_yield()这个函数可以使用另一个级别等于或高于当前线程的线程先运行。如果没有符合条件的线程,那么这个函数将会立刻返回然后继续执行当前线程的程序.
2.3线程死了之后就不能被开启。
2.4[NSThread sleepForTimeInterval:2.0]; 阻塞
2.5 cancel finished.
如果刚开始就被cancel了 线程中的任务没有执行,所以就不会执行。
如果任务开始了,cancel 这个线程,任务不会停止,直到执行完。
exit可以停止线程。杀掉主线程,但app不会挂掉,后面的代码不会执行。
3.GCD:
任务的执行方式:同步任务,异步任务,
队列的调度:队列是用来调度任务的,串行,并发。
3.1dispatch_async(queue,block) async 异步队列,dispatch_async 函数会立即返回, block会在后台异步执行。
dispatch_sync(queue,block) sync 同步队列,dispatch_sync 函数不会立即返回,及阻塞当前线程,等待 block同步执行完成。
dispatch_sync(dispatch_get_main_queue() ^{
});
主队列 会在主线程执行
同步主队列
同步串行队列
同步并行
异步主队列
异步串行
dispatch_queue_t q = dispatch_queue_create("tanzhouios", NULL);
异步并行
dispatch_queue_t q = dispatch_queue_create("tanzhou", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(q, ^{
NSLog(@"%@ %d",[NSThread currentThread],i);
});
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
有一个互斥锁。
dispatch_once(&onceToken, ^{
//只会执行一次!!
NSLog(@"执行了%@",[NSThread currentThread]);
});
GCD延时执行:
dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
dispatch_after(when, dispatch_queue_create("tanzhou", NULL), ^{
NSLog(@"%@",[NSThread currentThread]);
});
异步组:
dispatch_group_async()
栅栏-多读单写。
dispatch_barrier_async()
-
NSOperation 是一个抽象类,不具备操作的能力,必须使用他的子类。
NSInvacationOperation
NSBlockOperation
添加任务依赖:
任务执行状态控制:
4.1
start()自行控制任务状态。执行状态。
start (){
main()底层控制变更任务执行完成状态,以及任务退出。
}
状态改变-KVO的方式:
系统怎么移除一个isFinished = YES 的NSOperation的?
答案:通过KVO.的方式。4.2 最大并发数
最大并发数量如果是2 会保持最多有两个线程在执行,线程没有任务会被回收,重新创建线程
4.3 暂停&恢复
如果队列被挂起,就不在队列里面拿操作了。
如果挂起队列的时候,正在执行的任务不会暂停。
队列的 cancelAll
队列的 isSuspended 暂停 继续。
[op2 addDependency:op1];//op2 依赖于 op1 == op1 执行完毕 op2 开始执行
[op3 addDependency:op2];
// !!千万注意!!!: 不要循环依赖!!!!,一旦指定了循环依赖,队列就不能执行被循环依赖的操作了!!
//不会造成死锁! 但是 以前的版本 会死锁!!
5.锁:
自旋锁:
OSSpinLock 自旋锁(虽然已经被证明不安全 优先级翻转),性能最高的锁。原理很简单,就是一直 do while 忙等。它的缺点是当等待时会消耗大量 CPU 资源,所以它不适用于较长时间的任务。对于内存缓存的存取来说,它非常合适。
自旋锁。循环等待访问,不释放资源。
具体来说,如果一个低优先级的线程获得锁并访问共享资源,这时一个高优先级的线程也尝试获得这个锁,它会处于 spin lock 的忙等状态从而占用大量 CPU。此时低优先级线程无法与高优先级线程争夺 CPU 时间,从而导致任务迟迟完不成、无法释放 lock。这并不只是理论上的问题,libobjc 已经遇到了很多次这个问题了,于是苹果的工程师停用了 OSSpinLock。主要原因发生在低优先级线程拿到锁时,高优先级线程进入忙等(busy-wait)状态,消耗大量 CPU 时间,从而导致低优先级线程拿不到 CPU 时间,也就无法完成任务并释放锁。这种问题被称为优先级反转
互斥锁:如果共享数据已经有其他线程加锁了,线程会进入休眠状态等待锁。一旦被访问的资源被解锁,则等待资源的线程会被唤醒。
自旋锁:如果共享数据已经有其他线程加锁了,线程会以死循环的方式等待锁,一旦被访问的资源被解锁,则等待资源的线程会立即执行。
自旋锁的效率高于互斥锁。
查看 CoreFoundation 的源码能够发现,苹果至少在 2014 年就发现了这个问题,并把CoreFoundation 中的 spinlock 替换成了 pthread_mutex。
信号量
pthread_mutex 不是使用忙等,而是阻塞线程并睡眠.
信号量:
dispatch_semaphore_create(信号量值)
//等待降低信号量
dispatch_semaphore_wait
//提高信号量
dispatch_semaphore_signal
假设现在系统有两个空闲资源可以被利用,但同一时间却有三个线程要进行访问,这种情况下,该如何处理呢?
或者
我们要下载很多图片,并发异步进行,每个下载都会开辟一个新线程,可是我们又担心太多线程肯定cpu吃不消,那么我们这里也可以用信号量控制一下最大开辟线程数。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
1.dispatch_semaphore_create:创建一个Semaphore并初始化信号的总量
2.dispatch_semaphore_signal:发送一个信号,让信号总量加1
3.dispatch_semaphore_wait:可以使总信号量减1,当信号总量为0时就会一直等待(阻塞所在线程),否则就可以正常执行。类似于停车位。
递归锁:
NSRecursiveLock 递归锁。重入
NSLock:[lock. lock];[lock. unlock];
方法再一个 [lock. lock];[lock. unlock];会重入,
@synchronized 单列对象时候使用。保证对象是唯一的。
Atomic: nsmutableArray 付给值是安全的。但是添加和操作这个array是不安全的。