【iOS】—— pthread、NSThread

pthread

1.概念

pthread是一套通用的多线程API,可以在Unix/Linux/Windows等系统跨平台使用。使用C语言编写,需要程序员自己管理线程的生命周期,使用难度比极大,我们在iOS开发中几乎不适用pthread,但是我们可以来了解一下。

  • 全称 POSIX Thread,POSIX(Portable Operating System Interface)表示可移植操作系统接口;
  • 一套用 C 语言写的通用的多线程 API;
  • 适用于 Unix / Linux / Windows 等系统;
  • 跨平台/可移植;
  • 使用难度大、使用频率低;
  • 线程生命周期由程序员管理;
  • 现在 iOS 中用到 pthread 的多数情况是使用 pthread_mutex 互斥锁,性能较高。

2.pthread的使用

  • 添加头文件#import <pthread.h>
  • 创建线程,并开启线程执行任务
pthread_create() // 创建一个线程
pthread_exit() // 终止当前线程
pthread_cancel() // 中断另外一个线程的运行
pthread_join() // 阻塞当前的线程,直到另外一个线程运行结束
pthread_attr_init() // 初始化线程的属性
pthread_attr_setdetachstate() // 设置脱离状态的属性(决定这个线程在终止时是否可以被结合)
pthread_attr_getdetachstate() // 获取脱离状态的属性
pthread_attr_destroy() // 删除线程的属性
pthread_kill() // 向线程发送一个信号

举例使用:

void *run(void *param) {    // 新线程调用方法,里边为需要执行的任务
   NSLog(@"%@", [NSThread currentThread]);

   return NULL;
}

int main(int argc, const char * argv[]) {
    // 1. 创建线程: 定义一个pthread_t类型变量
    pthread_t thread;
    // 2. 开启线程: 执行任务
    pthread_create(&thread, NULL, run, NULL);
    // 3. 设置子线程的状态设置为 detached,该线程运行结束后会自动释放所有资源
    pthread_detach(thread);
    NSLog(@"%@", [NSThread currentThread]); // 如果不要这一行,很可能直接return 0,线程还没调用,直接return 0了
    return 0;
}
/*
create中间有4个参数
第一个:线程编号的地址
第二个:线程属性,默认为NULL
第三个:线程要执行的函数 void * (*)(void *)
第四个:函数的参数,参数类型:void *
返回值:0代表成功,非0代表失败
 */

输出结果:
534534534

就是这个用起来感觉太繁琐了,很古老,用了其他的再用这个感觉就是降维打击。。。

NSThread

1.概念

NSThread 是苹果官方提供的,使用起来比 pthread 更加面向对象,简单易用,可以直接操作线程对象。不过也需要需要程序员自己管理线程的生命周期(主要是创建),我们在开发的过程中偶尔使用 NSThread。比如我们会经常调用[NSThread currentThread]来显示当前的进程信息。

  • 使用更加面向对象;
  • 简单易用,可直接操作线程对象;
  • 语言 OC,线程生命周期由程序员管理,偶尔使用。

2.创建、启动线程

先创建线程,再启动线程:

// 方式一:
// 1.创建线程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
// 2.启动线程
[thread start]; // 线程一启动就会执行其中的 run 方法

- (void)run {
    NSLog(@"%@", [NSThread currentThread]);
}


// 方式二:
NSThread *thread = [[NSThread alloc] initWithBlock:^{
    NSLog(@"%@", [NSThread currentThread]);
}];
[thread start];

输出结果:
5345345

创建线程后自动启动线程

// 方式一:
// 创建线程后自动启动线程
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];

- (void)run {
    NSLog(@"%@", [NSThread currentThread]);
}


// 方式二:
[NSThread detachNewThreadWithBlock:^{
	NSLog(@"%@", [NSThread currentThread]);
}];

输出结果:
5345345

隐式创建并启动线程

[self performSelectorInBackground:@selector(run) withObject:nil];

- (void)run {
    NSLog(@"%@", [NSThread currentThread]);
}

输出结果:
4234234

3.线程相关用法

// 获得主线程
+ (NSThread *)mainThread;

// 判断是否为主线程
- (BOOL)isMainThread;
+ (BOOL)isMainThread;

// 获得当前线程
NSThread *current = [NSThread currentThread];

// 线程的名字——setter方法
- (void)setName:(NSString *)n;

// 线程的名字——getter方法
- (NSString *)name;

4.线程状态控制方法

启动方法

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

阻塞(暂停)线程方法

+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;// 这里的参数是NSTimeInterval类型的,其值始终是以秒为单位的,直接用数字就行了
// 线程进入阻塞状态

强制停止线程

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

5.线程之间的通讯

我们常常会在子线程进行耗时操作,操作结束后回到主线程刷新UI,这就涉及到了子线程和主线程之间的通信:

// 在主线程上执行操作
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorOnMainThread:(SEL)aSelector WithObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray<NSString *> *)array;

// 在指定线程上执行操作
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);

// 在当前线程上执行操作,调用NSObject的performSelector:相关方法
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

我们平时使用网络请求的时候就经常需要回到主线程再进行操作,现在我们已经学到了很多回到主线程执行操作的方法了:

5.1 NSOperationQueue回到主线程操作
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
 	// 回到主线程的操作
}];
5.2 NSThread回到主线程操作
[self performSelectorOnMainThread:@selector(WantToGoBackMianThread:) withObject:nil waitUntilDone:YES];
/*
selector:执行的方法
arg:传给方法的参数
wait:为NO,不阻塞主线程的执行
	 为YES,阻塞主线程的执行
*/
- (void)WantToGoBackMianThread:(id)object{
     // 回到主线程的操作
}
5.3 GCD回到主线程操作
dispatch_async(dispatch_get_main_queue(), ^{
   // 回到主线程的操作
});

6.线程的状态、生命周期

4324234

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //新建状态
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
    //就绪状态
    [thread start];
}

- (void)demo {
    //运行状态
    for (int i = 0; i < 20; i++) {
        NSLog(@"%d",i);
        if (i == 5) {
            //阻塞状态
            [NSThread sleepForTimeInterval:5];
        }
        if (i == 10) {
            //线程退出,死亡状态
            [NSThread exit];
        }
    }
}

输出结果:
34234234

7.NSThread线程安全

线程安全解决的方案:给线程加锁,在一个线程执行该操作的时候,不允许其他线程进行操作。iOS实现线程加锁有很多种方式,@synchronizedNSLockNSRecursiveLockNSConditionNSConditionLockpthread_mutexdispatch_semaphoreOSSpinLockatomic(property) set/get等等各种方式,来保证线程安全,从而解决线程同步问题。

8.线程池的原理

5345345

参数名代表含义
corePoolSize线程池的基本大小(核心线程池大小)
maximumPoolSize线程池的最大大小
keepAliveTime线程池中超过 corePoolSize 数目的空闲线程的最大存活时间
unitkeepAliveTime 参数的时间单位
workQueue任务阻塞队列
threadFactory新建线程的工厂
handler当提交的任务数超过 maximumPoolSize 与 workQueue 之和时,任务会交给 RejectedExecutionHandler 来处理
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值