ToB企服应用市场:ToB评测及商务社交产业平台

标题: iOS ------ 多线程 pthread,NSThread [打印本页]

作者: 莱莱    时间: 2024-8-25 06:33
标题: iOS ------ 多线程 pthread,NSThread
一,pthread

1.1pthread简介

pthread是一套通用的多线程的API,可以在Unix/Linux/Windows等系统跨平台使用,使用C语言编写,需要程序员自己管理线程的生命周期,使用难度大。
1.2pthread使用方法

1,首先要包罗头文件#import<pthread.h>
2,其次要创建线程,并开启线程使命
  1. - (void)viewDidLoad {
  2.     [super viewDidLoad];
  3.     //创建线程,定义一个pthread类型变量,为指向线程的指针
  4.     pthread_t thread;
  5.     //定义一个OC对象用于传递参数
  6.     NSObject* obj = [[NSObject alloc] init];
  7.     NSLog(@"objc:%p", obj);
  8.     //开启线程:执行任务
  9.     int result  = pthread_create(&thread, NULL, run, (__bridge void*)(obj));
  10.     if (result == 0) {
  11.         NSLog(@"创建线程成功");
  12.     } else {
  13.         NSLog(@"创建线程失败");
  14.     }
  15.     //设置子线程的状态为detached,该线程结束自动释放所有资源
  16.     pthread_detach(thread);
  17.     NSLog(@"%@", [NSThread currentThread]);
  18.     // Do any additional setup after loading the view.
  19. }
  20. void * run(void* param) {
  21.     NSLog(@"%@ param: %p", [NSThread currentThread], param);
  22.     NSObject* instance = (__bridge NSObject*)parm;
  23.     [instance 调用方法];
  24.     return NULL;
  25. }
复制代码
上面将OC对象包装在符合签名的C函数中。
在创建线程时,我们将OC对象桥接为 void * 范例传递给 pthread_create。使用“桥接”(bridge)来处理指针范例转换是由于OC与C语言在内存管理和范例系统上存在差异。如果不使用桥接,ARC 可能以为对象不再需要管理,导致对象在转换后可能被释放。使用 __bridge 明白告诉 ARC 不要改变引用计数。
在函数中使用使用参数对象,调用他的方法。也需要使用桥接。如果没用使用桥接ARC 可能以为这是一个新的对象,需要增加引用计数。使用 __bridge 明白告诉 ARC 这是一个已有对象,不要改变引用计数。
pthread_create 是一个标准的 C 语言函数,用于创建一个新线程。它的函数签名如下:
  1. int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
  2.                    void *(*start_routine) (void *), void *arg);
复制代码

1.3 pthread 其他干系方法

二,NSThead

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


  1. // 1. 创建线程
  2. NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
  3. // 2. 启动线程
  4. [thread start];    // 线程一启动,就会在线程thread中执行self的run方法
  5. // 新线程调用方法,里边为需要执行的任务
  6. - (void)run {
  7.      NSLog(@"%@", [NSThread currentThread]);
  8. }
复制代码

  1. // 1. 创建线程后自动启动线程
  2. [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
  3. // 新线程调用方法,里边为需要执行的任务
  4. - (void)run {
  5.      NSLog(@"%@", [NSThread currentThread]);
  6. }
复制代码

  1. // 1. 隐式创建并启动线程
  2. [self performSelectorInBackground:@selector(run) withObject:nil];
  3. // 新线程调用方法,里边为需要执行的任务
  4. - (void)run {
  5.      NSLog(@"%@", [NSThread currentThread]);
  6. }
复制代码
2.2,线程干系方法

  1. // 获得主线程
  2. + (NSThread *)mainThread;   
  3. // 判断是否为主线程(对象方法)
  4. - (BOOL)isMainThread;
  5. // 判断是否为主线程(类方法)
  6. + (BOOL)isMainThread;   
  7. // 获得当前线程
  8. NSThread *current = [NSThread currentThread];
  9. // 线程的名字——setter方法
  10. - (void)setName:(NSString *)n;   
  11. // 线程的名字——getter方法
  12. - (NSString *)name;   
复制代码
2.3线程状态控制方法

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

  1. + (void)sleepUntilDate:(NSDate *)date;
  2. + (void)sleepForTimeInterval:(NSTimeInterval)ti;
  3. // 线程进入阻塞状态
复制代码

  1. + (void)exit;
  2. // 线程进入死亡状态
复制代码
2.4,线程之间的通信
在开辟中,我们通常会在子线程进行耗时操作,操作结束后在回到主线程去革新UI,这就涉及到子线程和主线程之间的通信。官方关于 NSThread 的线程间通信的方法。
  1. // 在主线程上执行操作
  2. - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
  3. - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray<NSString *> *)array;
  4.   // equivalent to the first method with kCFRunLoopCommonModes
  5. // 在指定线程上执行操作
  6. - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array NS_AVAILABLE(10_5, 2_0);
  7. - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
  8. // 在当前线程上执行操作,调用 NSObject 的 performSelector:相关方法
  9. - (id)performSelector:(SEL)aSelector;
  10. - (id)performSelector:(SEL)aSelector withObject:(id)object;
  11. - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
复制代码
一个下载图片的例子,先开启一个子线程,在子线程中下载图片。再回到主线程革新 UI,将图片展示在 UIImageView 中。
  1. - (void)viewDidLoad {
  2.     [super viewDidLoad];
  3.     self.imageView = [[UIImageView alloc] init];
  4.     self.imageView.frame = CGRectMake(100, 100, 100, 100);
  5.     [self.view addSubview:self.imageView];
  6.      [self downloadImageOnSubThread];
  7. }
  8. - (void)downloadImageOnSubThread {
  9.     //在创建的子线程调用downloadImage下载图片
  10.     [NSThread detachNewThreadSelector:@selector(downloadImage) toTarget:self withObject:nil];
  11. }
  12. - (void)downloadImage {
  13.     NSLog(@"current thread -- %@", [NSThread currentThread]);
  14.     NSURL* imageUrl = [NSURL URLWithString:@"https://ysc-demo-1254961422.file.myqcloud.com/YSC-phread-NSThread-demo-icon.jpg"];
  15.    
  16.     //从imageURL中读取图片(下载图片)耗时操作
  17.     NSData* imageData = [NSData dataWithContentsOfURL:imageUrl];
  18.     //痛过二进制data创建image
  19.     UIImage* image = [UIImage imageWithData:imageData];
  20.    
  21.     //回到主线程进行图片的赋值和页面的刷新
  22.     [self performSelectorOnMainThread:@selector(refreshOnMainThread:) withObject:image waitUntilDone:YES];
  23. }
  24. - (void)refreshOnMainThread:(UIImage*) image {
  25.     NSLog(@"current thread -- %@", [NSThread currentThread]);
  26.    
  27.     //将图片复制到imageView上
  28.     self.imageView.image = image;
  29. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4