进程与线程的关系

进程是指在系统中正在运行的一个应用程序。每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程,称为主线程)。一个进程(程序)的所有任务都在线程中执行,
同一时间,CPU只能处理1条线程,只有1条线程在工作(执行),多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换),如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象。

NSThread

NSThread是OC线程的基础类,可以通过start sleep cancel控制线程执行情况。

// 方法一:创建线程,需要自己开启线程(可控制)NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run) object:nil];// 开启线程[thread start];// 方法二:创建线程后自动启动线程[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];// 方法三:隐式创建并启动线程[self performSelectorInBackground:@selector(run) withObject:nil];

GCD

GCD会自动利用更多的CPU内核
GCD自动管理线程的生命周期(创建线程,调度任务,销毁线程等)

GCD中有2个核心概念:任务和队列
任务
同步:只能在当前线程中执行任务,不具备开启新线程的能力,任务立刻马上执行,会阻塞当前线程并等待 Block中的任务执行完毕,然后当前线程才会继续往下运行
异步:可以在新的线程中执行任务,具备开启新线程的能力,但不一定会开新线程,当前线程会直接往下执行,不会阻塞当前线程

队列
判定一些操作往一个队列中添加时如何执行,先看是往串行还是并行队列中加任务,如是串行必然是顺序执行的,如果是并行异步才会交叉执行。
//全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 串行队列
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
// 并发队列
dispatch_queue_t queue1 = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);

栅栏函数可以控制任务执行的顺序,栅栏函数之前的执行完毕之后,执行栅栏函数,然后在执行栅栏函数之后的(并发队列)
dispatch_barrier_async(queue, ^{ });

队列组
当有多个异步任务的时候,组内全部执行完毕再执行dispatch_group_notify可以起到监听作用,控制业务流程。

 // 创建队列组dispatch_group_t group = dispatch_group_create();// 创建并行队列dispatch_queue_t queue = dispatch_get_global_queue(0, 0);// 执行队列组任务dispatch_group_async(group, queue, ^{NSLog(@"异步任务1");});// 执行队列组任务dispatch_group_async(group, queue, ^{NSLog(@"异步任务2");});//队列组中的任务执行完毕之后,执行该函数dispatch_group_notify(group, queue, ^{NSLog(@"组内执行完毕任务,此处执行");});

信号量

// 创建信号量,并且设置值为0dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_async(queue, ^{//发送一个信号,自然会让信号总量加1,dispatch_semaphore_signal(semaphore);});//阻塞主线程//当信号总量少于0的时候就会一直等待,否则就可以正常的执行,并让信号总量-1dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);NSLog(@"等待信号量大于0才会执行”);//利用信号量进行并发控制(5次)dispatch_semaphore_t sema = dispatch_semaphore_create(5);for (100次循环操作) {dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{// 操作dispatch_semaphore_signal(sema);});}

dispatch_group_enter和dispatch_group_leave
利用dispatch_group_enter和dispatch_group_leave控制线程,因为二者必须一一对应,只有leave之后,才能进行下一个enter。如:利用这两个函数实现AFNetWorking多个请求依赖的线程同步问题,这样就能让下一个异步请求在上一个执行完毕后再执行。而不需要写在回调内。

dispatch_group_t group = dispatch_group_create();dispatch_group_enter(group);AFNetWorking{dispatch_group_leave(group);NSLog(@"异步任务1");}dispatch_group_enter(group);AFNetWorking{dispatch_group_leave(group);NSLog(@“异步任务2");}   dispatch_group_notify(group, queue, ^{NSLog(@"组内执行完毕任务,此处执行");});

NSOperationQueue

NSOperation 是苹果公司对 GCD 的封装,完全面向对象,并比GCD多了一些更简单实用的功能,所以使用起来更加方便易于理解,主要优势有设置依赖,优先级设置,可继承,键值对观察。NSOperation 和NSOperationQueue 分别对应 GCD 的 任务 和 队列。
NSOperation和NSOperationQueue实现多线程的具体步骤
1.将需要执行的操作封装到一个NSOperation对象中
2.将NSOperation对象添加到NSOperationQueue中
系统会自动将NSOperationQueue中的NSOperation取出来,并将取出的NSOperation封装的操作放到一条新线程中执行
如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
3.最大并发数:当maxConcurrentOperationCount为1时,则表示不开线程,也就是串行,默认为-1,大于1都为并行。
4.NSOperationQueue可以cancel,suspend(暂停)。暂停和取消不是立刻取消当前操作,而是等当前的操作执行完之后不再进行新的操作

操作依赖

// 创建非主队列NSOperationQueue *queue = [[NSOperationQueue alloc]init];// 下载第一张图片NSBlockOperation *download1 = [NSBlockOperation blockOperationWithBlock:^{}];// 下载第二张图片NSBlockOperation *download2 = [NSBlockOperation blockOperationWithBlock:^{}];// 合成操作NSBlockOperation *combie = [NSBlockOperation blockOperationWithBlock:^{// 回到主线程刷新UI[[NSOperationQueue mainQueue]addOperationWithBlock:^{//合成图片}];}];// 添加依赖,合成图片需要等图片1,图片2都下载完毕之后合成[combie addDependency:download1];[combie addDependency:download2];// 添加操作到队列[queue addOperation:download1];[queue addOperation:download2];[queue addOperation:combie];

读写锁

self.concurrentQueue = dispatch_queue_create("aaa", DISPATCH_QUEUE_CONCURRENT);
// 写操作,栅栏函数是不允许并发的,所以"写操作"是单线程进入的,根据log可以看出来
- (void)setText:(NSString *)text {__weak typeof(self) weakSelf = self;dispatch_barrier_sync(self.concurrentQueue, ^{__strong typeof(weakSelf) strongSelf = weakSelf;strongSelf->_text = text;NSLog(@"写操作 %@ %@",text,[NSThread currentThread]);// 模拟耗时操作,1个1个执行,没有并发sleep(1);});
}
// 读操作,这个是可以并发的,log在很快时间打印完
- (NSString *)text {__block NSString * t = nil ;__weak typeof(self) weakSelf = self;dispatch_sync(self.concurrentQueue, ^{__strong typeof(weakSelf) strongSelf = weakSelf;t = strongSelf->_text;// 模拟耗时操作,瞬间执行完,说明是多个线程并发的进入的sleep(1);});return t;}

互斥锁,模拟抢票,多个线程同时访问和改变一个变量

-(void)saleTicket
{while (1) {// 创建对象// self.obj = [[NSObject alloc]init];// 锁对象,本身就是一个对象,所以self就可以了// 锁定的时候,其他线程没有办法访问这段代码@synchronized (self) {// 模拟售票时间,我们让线程休息0.05s[NSThread sleepForTimeInterval:0.05];if (self.numTicket > 0) {self.numTicket -= 1;NSLog(@"%@卖出了一张票,还剩下%zd张票",[NSThread currentThread].name,self.numTicket);}else{NSLog(@"票已经卖完了");break;}}//使用NSLock对象也可以实现NSLock *lock = [[NSLock alloc]init];[lock lock];//Safe[lock unlock];}
}

如果将numTicket对象设置为atomic则默认会使用互斥锁,等同于@synchronized (self)
@property(automic,assign)NSInteger numTicket;

一个进程的内存分配

每个区域实际上都存储相应的内容,其中代码区、常量区、静态区这三个区域都是自动加载,并且在进程结束之后被系统释放,开发者并不需要进行关注。

栈区一般存放局部变量、临时变量,由编译器自动分配和释放,每个线程运行时都对应一个栈。而堆区用于动态内存的申请,由程序员分配和释放。一般来说,栈区由于被系统自动管理,速度更快,但是使用起来并不如堆区灵活。

对于 Swift 来说,值类型存于栈区,引用类型存于堆区。值类型典型的有 struct、enum 以及 tuple 都是值类型。而比如 Int、Double、Array,Dictionary 等其实都是用结构体实现的,也是值类型。而 class、closure 都是引用类型,也就是说 Swift 中我们如果遇到类和闭包,就要留个心眼,考虑一下他们的引用情况。

iOS-进程、线程、锁相关推荐

  1. 嵌入式 linux 进程锁,嵌入式  Linux线程锁详解pthread_mutexattr_t

    在Posix Thread中定义有一套专门用于线程同步的mutex函数. 1. 创建和销毁 有两种方法创建互斥锁,静态方式和动态方式.POSIX定义了一个宏PTHREAD_MUTEX_INITIALI ...

  2. 分布式锁,进程锁,线程锁到底是什么

    在分布式集群系统的开发中,线程锁往往并不能支持全部场景的使用,必须引入新的技术方案分布式锁. 线程锁:大家都不陌生,主要用来给方法.代码块加锁.当某个方法或者代码块使用锁时,那么在同一时刻至多仅有有一 ...

  3. python是如何实现进程池和线程池的_高并发:线程、线程锁与线程池(精华),手写代码实现线程池...

    前文: 单线程--多线程的开启--线程锁--线程同步工具--手写连接池--连接池工具类. 一.线程 1.线程的概念 2.线程与进程的关系 3.定义: 区别:如上!!! 4.wait()和sleep() ...

  4. 一句话说清分布式锁,进程锁,线程锁

    一句话说清分布式锁,进程锁,线程锁 在分布式集群系统的开发中,线程锁往往并不能支持全部场景的使用,必须引入新的技术方案分布式锁. 线程锁,进程锁,分布式锁 线程锁:大家都不陌生,主要用来给方法.代码块 ...

  5. iOS线程锁中你还不知道的内容

    iOS线程锁 一:十种线程锁 我们在使用多线程的时候多个线程可能会访问同一块资源,这样就很容易引发数据错乱和数据安全等问题,这时候就需要我们保证每次只有一个线程访问这一块资源,锁 应运而生. 这里顺便 ...

  6. 正在等待缓存锁:无法获得锁_一句话说清分布式锁,进程锁,线程锁

    推荐阅读 1. Java 性能优化:教你提高代码运行的效率 2. Java问题排查工具清单 3. 记住:永远不要在MySQL中使用UTF-8 4. Springboot启动原理解析 在分布式集群系统的 ...

  7. 【JAVA SE】第十六章 进程、线程、同步锁和线程锁的简介

    第十六章 进程.线程.同步锁和线程安全问题 文章目录 第十六章 进程.线程.同步锁和线程安全问题 一.进程 1.基本介绍 2.进程模型 二.线程 1.基本介绍 2.线程的生命周期 3.线程的优先级 4 ...

  8. Python之进程+线程+协程(并发与并行、GIL锁、同步锁、死锁、递归锁)

    文章目录 一.并发与并行 二.同步与异步 三.线程锁 1.GIL全局解释器锁 2.同步锁 3.死锁 4.递归锁 在Python中GIL解释器锁.同步锁.死锁.递归锁都是什么?怎么这么多锁,它们都是用来 ...

  9. 进程互斥锁,队列,IPC进程间通信,生产者与消费者,线程,线程对象的属性,先行互斥锁...

    进程互斥锁: 让并发变成串行, 牺牲了执行效率, 保证了数据安全.在程序并发执行时,需要修改数据时使用. 队列 队列:先进先出 ​ 相当于内存中产生一个队列空间,先进先出, ​ 可以存放多个数据,但数 ...

  10. Python 第八篇:异常处理、Socket语法、SocketServer实现多并发、进程和线程、线程锁、GIL、Event、信号量、进程间通讯...

    本节内容: 异常处理.Socket语法.SocketServer实现多并发.进程和线程.线程锁.GIL.Event.信号量.进程间通讯.生产者消费者模型.队列Queue.multiprocess实例 ...

最新文章

  1. 干货 | 20多门AI网络课程资源(附链接)
  2. Selenium高亮页面对象
  3. linux的platform驱动
  4. mysql 时区设定_如何设置MySQL 时区
  5. prometheus 发送恢复 值_Prometheus监控神器-Rules篇
  6. 上海应用技术学院c语言实验报告9,上海工程技术大学C语言实验报告
  7. UNIX(多线程):23---线程池注意事项和常见问题
  8. 我们在使用计算机时,不能做什么?,11秋季学期计算机应用技术基础学习周期_01任务-在线作业[1]1...
  9. 215.数组中的第K个最大元素/347. 前 K 个高频元素
  10. 【转】各种树:trie树、B树、B-树、B+树、B*树
  11. python字符串描述_Python字符串
  12. Astah 7.2 安装
  13. 分蛋糕、思路视频(动态规划)
  14. 点餐系统mysql设计,SpringBoot 微信点餐系统 1:数据库表设计
  15. MySQL两种存储引擎: MyISAM和InnoDB 简单总结
  16. 自已动手修改同花顺K线周期的快捷键
  17. 怎么实现EDIUS中添加的图片素材一样大
  18. 关于stable diffusion的embedding训练的一篇随笔
  19. 拼多多商家制作商品详情页的技巧?
  20. 关于 Shell 脚本的经典十三问

热门文章

  1. dig命令-dns查询
  2. Docker容器网络实例管理
  3. MyBatisPlus查询时报错,Unknow column ‘id‘ in ‘field list‘,怎么解决?
  4. 人脸表情识别 项目实战
  5. serverlet 原理_容器原理架构详解(全)
  6. 计算机408知识点大全,2022计算机408考研知识点:输入输出系统
  7. Excel数据表格操作01~~使用JXL操作数据
  8. 将网络驱动器从XP映射到Windows 7
  9. ModuleNotFoundError: No module named 'lightgbm'
  10. 面试时回答离职原因的万能公式是什么?