【iOS】pthread、NSThread

ops/2024/9/23 20:12:28/

文章目录

  • 前言
  • 一、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.ppmy.cn/ops/31711.html

相关文章

matlab期末知识

1.期末考什么&#xff1f; 1.1 matlab操作界面 &#xff08;1&#xff09;matlab主界面 &#xff08;2&#xff09;命令行窗口 &#xff08;3&#xff09;当前文件夹窗口 &#xff08;4&#xff09;工作区窗口 &#xff08;5&#xff09;命令历史记录窗口 1.2 matlab搜索…

【网络】tcp协议如何保证可靠性

TCP&#xff08;Transmission Control Protocol&#xff09;是一种面向连接的、可靠的传输层协议&#xff0c;为网络通信提供了可靠性和连接稳定性。本文将详细介绍 TCP 协议如何保证数据的可靠传输和连接的稳定性&#xff0c;并分析其优缺点。 可靠性保证 序号和确认机制&…

3GPP官网下载协议步骤

1.打开官网 https://www.3gpp.org/ 2.点击 3.在界面选择要找的series&#xff0c;跳转到查找界面 以V2X通信协议为例&#xff0c;论文中通常会看到许多应用&#xff1a; [7] “Study on evaluation methodology of new Vehicle-to-Everything (V2X) use cases for LTE and NR…

普通二维码打开微信小程序并且传递参数

实现方法&#xff1a; 【1】确保有一个企业级别的认证过的微信小程序 【2】有一个https并且备案过的域名 【3】进入微信后台“开发”-“开发设置”-“扫普通链接二维码打开小程序”-“添加” 官方文档&#xff1a;https://developers.weixin.qq.com/miniprogram/introduction/q…

【方案解决思路】RPC服务器不可用

当在SCCM服务器上使用wmic /node:<客户端IP> process list命令时&#xff0c;如果遇到“RPC服务器不可用”的错误&#xff0c;这通常意味着SCCM服务器无法通过RPC协议与远程客户端通信。以下是一些可能的解决步骤&#xff1a; 检查远程客户端的RPC服务&#xff1a; 确保远…

【记录】Python3| 将 PDF 转换成 HTML/XML(✅⭐⭐⭐⭐pdf2htmlEX)

本文将会被汇总至 【记录】Python3&#xff5c;2024年 PDF 转 XML 或 HTML 的第三方库的使用方式、测评过程以及对比结果&#xff08;汇总&#xff09;&#xff0c;更多其他工具请访问该文章查看。 文章目录 pdf2htmlEX 使用体验与评估1 安装指南2 测试代码3 测试结果3.1 转 HT…

基于微服务和DDD的架构模板

基于微服务和DDD的架构模板 常用技术选型逻辑架构模板基于DDD的代码结构模板 常用技术选型 反向代理&#xff1a;Nginx开发框架&#xff1a;Spring Boot数据库&#xff1a;MySQL缓存&#xff1a;Redis微服务解决方案&#xff1a;Spring Cloud Alibaba 注册中心&#xff1a;Nac…

Spring Boot微服务架构实战

Spring Boot微服务架构实战是一个涉及到多个关键技术和步骤的过程&#xff0c;以下是关于其详细论述&#xff1a; 一、微服务架构概述 微服务架构是一种将单个应用程序拆分为一组小的服务的方法&#xff0c;每个服务都运行在其独立的进程中&#xff0c;服务与服务之间通过轻量…