【iOS】pthread、NSThread

文章目录

  • 前言
  • 一、pthread 使用方法
    • pthread 其他相关方法
  • 二、 NSThread
    • 创建、启动线程
    • 线程相关用法
    • 线程状态控制方法
    • NSThread 线程安全和线程同步
    • 场景
  • 线程的状态转换


前言

五一这两天准备将GCD相关的知识完,同时NSOperationNSThread、pthread也是相关知识,这一篇文章主要讲解NSThread、pthread的学习

pthread是一套用C语言编写的多线程API,可以在Unix / Linux / Windows 等系统跨平台使用,尽管现在已经不常用,但是还是可以了解

一、pthread 使用方法

1、导入头文件#import <pthread.h>
2、其次创建线程执行任务

void* run(void *param) {NSLog(@"%@", [NSThread currentThread]);return nil;
}- (void)viewDidLoad {[super viewDidLoad];pthread_t thread;pthread_create(&thread, NULL, run, NULL);pthread_detach(thread);
}

pthread_create(&thread, NULL, run, NULL); 中各项参数含义:

  • 第一个参数&thread是线程对象,指向线程标识符的指针
  • 第二个是线程属性,可赋值NULL
  • 第三个run表示指向函数的指针(run对应函数里是需要在新线程中执行的任务)
  • 第四个是运行函数的参数,可赋值NULL

这里有一个注意点: 在 CObjective-C 中,线程的启动函数需要具备特定的签名。对于
pthread_create,期望的线程函数必须返回一个 void * 并接受一个 void *
参数。具体来说,函数类型应该是:
void *ThreadFunction(void *arg);

pthread 其他相关方法

pthread_create() //创建一个线程
pthread_exit() //终止当前线程
pthread_cancel() //中断另外一个线程的运行
pthread_join() //阻塞当前的线程,直到另外一个线程运行结束
pthread_attr_init() //初始化线程的属性
pthread_attr_setdetachstate() //设置脱离状态的属性(决定这个线程在终止时是否可以被结合)
pthread_attr_getdetachstate() //获取脱离状态的属性
pthread_attr_destroy() //删除线程的属性
pthread_kill() //向线程发送一个信号

二、 NSThread

NSThread是苹果官方提供的,使用起来更加面向对象,简单易用,可以直接操作线程对象

我们在开发的过程中偶尔使用 NSThread。比如我们会经常调用[NSThread currentThread]来显示当前的进程信息。

创建、启动线程

  • 先创建线程再启动线程
    // 1. 创建线程NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];// 2. 启动线程[thread start];    // 线程一启动,就会在线程thread中执行self的run方法// 新线程调用方法,里边为需要执行的任务
- (void)run {NSLog(@"%@", [NSThread currentThread]);
}
  • 创建线程后自动启动线程
// 1. 创建线程后自动启动线程
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];// 新线程调用方法,里边为需要执行的任务- (void)run {NSLog(@"%@", [NSThread currentThread]);
}
  • 隐式创建并启动线程
// 1. 隐式创建并启动线程
[self performSelectorInBackground:@selector(run) withObject:nil];// 新线程调用方法,里边为需要执行的任务
- (void)run {NSLog(@"%@", [NSThread currentThread]);
}

线程相关用法

// 获得主线程
+ (NSThread *)mainThread;    // 判断是否为主线程(对象方法)
- (BOOL)isMainThread;// 判断是否为主线程(类方法)
+ (BOOL)isMainThread;    // 获得当前线程
NSThread *current = [NSThread currentThread];// 线程的名字——setter方法
- (void)setName:(NSString *)n;    // 线程的名字——getter方法
- (NSString *)name;    

线程状态控制方法

启动线程方法:

- (void)start;
// 线程进入就绪状态 -> 运行状态。当线程任务执行完毕,自动进入死亡状态

阻塞(暂停)线程方法:

+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 线程进入阻塞状态

强制停止线程:

+ (void)exit;
// 线程进入死亡状态

NSThread 线程安全和线程同步

  • 线程安全:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

如果每个线程对于全局变量,静态变量都只有读取的操作,说明变量是线程安全的,如果使用多线程进行读写操作,就必须要考虑线程同步

  • 线程同步:有两个线程A与B,A与B相互依赖,A 执行到一定程度时要依靠线程 B 的某个结果,于是停下来,示意 B 运行;B 依言执行,再将结果给 A;A 再继续操作。

例子:
两个人在一起聊天。两个人不能同时说话,避免听不清(操作冲突)。等一个人说完(一个线程结束操作),另一个再说(另一个线程再开始操作)。

场景

我们用一个经典的模拟售票的例子实现 NSThread 线程安全和解决线程同步问题。

场景:总共有50张火车票,有两个售卖火车票的窗口,一个是北京火车票售卖窗口,另一个是上海火车票售卖窗口。两个窗口同时售卖火车票,卖完为止。

如果线程非安全代码如下:

-(void)initTicketStatusNotSafe {// 1. 设置剩余火车票为 50self.ticketSurplusCount = 50;// 2. 设置北京火车票售卖窗口的线程NSThread *ticketSaleWindow1 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketNotSafe) object:nil];ticketSaleWindow1.name = @"北京火车票售票窗口";// 3. 设置上海火车票售卖窗口的线程NSThread *ticketSaleWindow2 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketNotSafe) object:nil];ticketSaleWindow2.name = @"上海火车票售票窗口";// 4. 开始售卖火车票[ticketSaleWindow1 start];[ticketSaleWindow2 start];}- (void)saleTicketNotSafe {while (1) {//如果还有票,继续售卖if ([NSThread currentThread] != [NSThread mainThread]) {if (self.ticketSurplusCount > 0) {self.ticketSurplusCount --;NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%ld 窗口:%@", self.ticketSurplusCount, [NSThread currentThread].name]);[NSThread sleepForTimeInterval:0.2];}//如果已卖完,关闭售票窗口else {NSLog(@"所有火车票均已售完");break;}}}
}

在这里插入图片描述
可以看到票序是混乱的

因为如果不对线程进行加锁可能在同一时间两个线程会访问同一资源,会造成当前结果,因此我们需要在一个线程执行该操作的时候,不允许其他线程进行操作

iOS 实现线程加锁有很多种方式。@synchronized、 NSLock、NSRecursiveLock、NSCondition、NSConditionLock、pthread_mutex、dispatch_semaphore、OSSpinLock、atomic(property) set/ge等等各种方式。为了简单起见,这里不对各种锁的解决方案和性能做分析,只用最简单的@synchronized来保证线程安全,从而解决线程同步问题。

线程安全代码:

- (void)saleTicketNotSafe {while (1) {//如果还有票,继续售卖@synchronized (self) {if ([NSThread currentThread] != [NSThread mainThread]) {if (self.ticketSurplusCount > 0) {self.ticketSurplusCount --;NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%ld 窗口:%@", self.ticketSurplusCount, [NSThread currentThread].name]);[NSThread sleepForTimeInterval:1];}//如果已卖完,关闭售票窗口else {NSLog(@"所有火车票均已售完");break;}}}}
}

在这里插入图片描述

线程的状态转换

当我们新建一条线程NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; ,在内存中的表现为:
在这里插入图片描述
当调用[thread start];后,系统把线程对象放入可调度线程池中,线程对象进入就绪状态,如下图所示。
在这里插入图片描述

当然,可调度线程池中,会有其他的线程对象
在这里插入图片描述

下边我们来看看当前线程的状态转换。
如果我们调用当前线程对象,当前线程就会进入运行状态,如果调度了其他线程对象,那么当前线程就会回到就绪状态

  • 如果CPU现在调度当前线程对象,则当前线程对象进入运行状态,如果CPU调度其他线程对象,则当前线程对象回到就绪状态。
  • 如果CPU在运行当前线程对象的时候调用了sleep方法或者等待同步锁,则当前线程对象就进入了阻塞状态,等到sleep到时或者得到同步锁,则回到就绪状态。
  • 如果CPU在运行当前线程对象的时候线程任务执行完毕或者异常强制退出,则当前线程对象进入死亡状态。
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/318621.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ffmpeg中stream_loop参数不生效原因分析

问题 使用ffmpeg把一个视频文件发布成一个rtmp流&#xff0c;并设置成循环推流&#xff0c;此时需要使用参数stream_loop&#xff0c;命令如下: ffmpeg.exe -stream_loop -1 -re -i D:\tools\ffmpeg-5.1.2\bin\sei.h264 -c copy -f flv -safe 0 rtmp://localhost:1935/live/te…

【Redis】Redis安装、配置、卸载使用可视化工具连接Redis

文章目录 1.前置条件2.安装Redis2.1下载Redis安装包并解压2.2在redis目录下执行make命令2.3修改Redis配置文件2.4启动Redis服务2.5连接redis服务 3.Redis卸载4.使用可视化工具连接Redis 1.前置条件 Linux操作系统需要要是64位.如果不清楚自己Linux上是多少位的,可以使用以下命…

Qt之信号与槽

槽的本质&#xff1a;对信号响应的函数。 信号函数和槽函数通常位于某个类中&#xff0c;和普通的成员函数相⽐&#xff0c;它们的特别之处在于&#xff1a; 信号函数⽤ signals 关键字修饰&#xff0c;槽函数⽤ public slots、protected slots 或者 private slots 修饰。sign…

数据结构:时间复杂度/空间复杂度

目录 一、时间复杂度 定义 常见的时间复杂度 如何计算时间复杂度 计算方法 三、实例分析 二、空间复杂度 定义 重要性 常见的空间复杂度 二、空间复杂度 定义 重要性 常见的空间复杂度 计算方法 三、实例分析 大O的渐进表示法 最好情况&#xff08;Best Case…

Java进阶-JINQ详解与使用

本文详细介绍了JINQ&#xff08;Java Integrated Query&#xff09;&#xff0c;一种强化Java中数据查询能力的库&#xff0c;提供类SQL的查询语法和类型安全的操作。文章首先解释了JINQ的基本功能和应用&#xff0c;随后通过具体示例展示了如何使用JINQ进行数据过滤、投影、连…

【竞技宝】意甲:退出齐尔克泽争夺战!国米免签伊朗神锋!

博洛尼亚中锋齐尔克泽成为了意甲当红炸子鸡,不少豪门球队都希望可以签下他,目前对球员有意向的俱乐部包括AC米兰、尤文图斯、阿森纳、国际米兰和曼联,看到自家球员如此有市场,博洛尼亚方面咬死5000万欧元的价格不松口,想要得到他必须要拿出真金白银。不过意甲霸主国际米兰率先退…

408数据结构-二叉树的概念、性质与存储结构 自学知识点整理

前置知识&#xff1a;树的基本概念与性质 二叉树的定义 二叉树是一种特殊的树形结构&#xff0c;其特点是每个结点至多只有两棵子树&#xff08;即二叉树中不存在度大于 2 2 2的结点&#xff09;&#xff0c;并且二叉树是有序树&#xff0c;左右子树不能互换。 与树类似&#…

笔试强训week3

day1 Q1 难度⭐ 牛牛冲钻五_牛客小白月赛38 (nowcoder.com) 题目&#xff1a; 牛牛最近在玩炉石传说&#xff0c;这是一款一对一对战的卡牌游戏&#xff0c;牛牛打算努力冲上钻五分段&#xff0c;获得丰厚的天梯奖励。 炉石传说的段位可以用星数来表示&#xff0c;具体规则…

【linuxC语言】空洞文件

文章目录 前言一、空洞文件1.1 空洞文件的介绍1.2 用途 二、示例代码总结 前言 在 Linux 系统编程中&#xff0c;空洞文件是一种特殊类型的文件&#xff0c;它包含了逻辑上的空洞&#xff0c;也就是说文件中的某些部分并没有实际写入数据。尽管文件在逻辑上可能非常大&#xf…

webpack 常用插件

clean-webpack-plugin 这个插件的主要作用是清除构建目录中的旧文件&#xff0c;以确保每次构建时都能得到一个干净的环境。 var { CleanWebpackPlugin } require("clean-webpack-plugin") const path require("path");module.exports {mode: "de…

Springboot+mybatis升级版(Postman测试)

一、项目结构 1.导入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apach…

12_Scala_package

文章目录 Scaal面向对象编程1.回顾Java2.package可以多次声明3.设置作用域&#xff0c;设置上下级4.包可以当作对象使用5.import6.Scala用_取代Java *7.导入多个包8.屏蔽类9.类起别名10.import的规则11.有些包无需导入 Scaal面向对象编程 Scala是一门完全面向对象语言&#xf…

Linux的权限管理

文章目录 文件权限文件类型文件访问者的分类文件权限的类型 文件访问权限的设置目录的权限 文件权限 对于每个LInux文件&#xff0c;如果用ll指令查看的话&#xff0c;可以发现每个文件前面都有一串类似的字符&#xff1a; 这里总共有十个字符&#xff0c;其中第一个字符表示…

QT httpServer多线程后台服务器的例子实现

1.需求 1.1 用户需要其他平台&#xff08;web端&#xff09;调用Qt平台的接口&#xff0c;获取想要的数据并实时显示在网页里&#xff0c;比如实时的温湿度&#xff0c;用户数据等 1.2 用户需要在其他平台&#xff08;web端&#xff09;调用Qt平台的接口&#xff0c;下发数据…

贝叶斯统计实战:Python引领的现代数据分析之旅

贝叶斯统计这个名字取自长老会牧师兼业余数学家托马斯贝叶斯(Thomas Bayes&#xff0c;1702—1761)&#xff0c;他最先推导出了贝叶斯定理&#xff0c;该定理于其逝世后的1763年发表。但真正开发贝叶斯方法的第一人是Pierre-Simon Laplace(1749—1827)&#xff0c;因此将其称为…

Copilot Venture Studio創始合伙人楊林苑確認出席“邊緣智能2024 - AI開發者峰會”

隨著AI技術的迅猛發展&#xff0c;全球正逐步進入邊緣計算智能化與分布式AI深度融合的新時代&#xff0c;共同書寫著分布式智能創新應用的壯麗篇章。邊緣智能&#xff0c;作為融合邊緣計算和智能技術的新興領域&#xff0c;正逐漸成為推動AI發展的關鍵力量。借助分布式和去中心…

Messari 报告摘要 :Covalent Network(CQT)2024 年第一季度表现

摘要&#xff1a; 尽管 CQT 代币流通供应量增加了 20%&#xff08;新增 1.04 亿枚 CQT&#xff09;&#xff0c;但 CQT 的质押百分比仅从 2023 年第一季度的 22% 增长到了 2024 年第一季度的 29%。 CQT 的市值季度环比增长了 28%&#xff0c;多次达到 2.75 亿美元&#xff0c…

分享三款可以给pdf做批注的软件

PDF文件不像Word一样可以直接编辑更改&#xff0c;想要在PDF文件上进行编辑批注需要用到一些专业的软件&#xff0c;我自己常用的有三款&#xff0c;全都是官方专业正版的软件&#xff0c;功能丰富强大&#xff0c;使用起来非常方便&#xff01; 1.edge浏览器 这个浏览器不仅可…

van-cascader(vant2)异步加载的bug

问题描述&#xff1a;由于一次性返回所有的级联数据的话&#xff0c;数据量太大&#xff0c;接口响应时间太久&#xff0c;因此采用了异步加载的方案&#xff0c;看了vant的官方示例代码&#xff0c;照着改了下&#xff0c;很轻松地实现了功能。正当我感叹世界如此美好的时候&a…

2.2 Java全栈开发前端+后端(全栈工程师进阶之路)-前端框架VUE3-基础-Vue基本语法

文本渲染指令 文本渲染指令-v-html与v-text Vue使用了基于HTML的模板语法&#xff0c;允许开发者声明式地将DOM绑定至底层Vue实例的数据。所有Vue的模板都是 合法的HTML&#xff0c;所以能被遵循规范的浏览器和HTML解析器解析。 在前面&#xff0c;我们一直使用的是字符串插…