线程

作者: 小哲哥哥2 | 来源:发表于2023-08-12 01:50 被阅读0次

    前言

    提到线程,那就不得不提CPU,现代的CPU有一个很重要的特性,就是时间片,每一个获得CPU的任务只能运行一个时间片规定的时间。

    其实线程对操作系统来说就是一段代码以及运行时数据。操作系统会为每个线程保存相关的数据,当接收到来自CPU的时间片中断事件时,就会按一定规则从这些线程中选择一个,恢复它的运行时数据,这样CPU就可以继续执行这个线程了。

    也就是其实就单核CUP而言,并没有办法实现真正意义上的并发执行,只是CPU快速地在多条线程之间调度,CPU调度线程的时间足够快,就造成了多线程并发执行的假象。并且就单核CPU而言多线程可以解决线程阻塞的问题,但是其本身运行效率并没有提高,多CPU的并行运算才真正解决了运行效率问题。

    系统中正在运行的每一个应用程序都是一个进程,每个进程系统都会分配给它独立的内存运行。也就是说,在iOS系统中中,每一个应用都是一个进程。

    一个进程的所有任务都在线程中进行,因此每个进程至少要有一个线程,也就是主线程。那多线程其实就是一个进程开启多条线程,让所有任务并发执行。

    多线程在一定意义上实现了进程内的资源共享,以及效率的提升。同时,在一定程度上相对独立,它是程序执行流的最小单元,是进程中的一个实体,是执行程序最基本的单元,有自己栈和寄存器。

    上面这些你是不是都知道,但是我偏要说,哦呵呵。既然我们聊线程,那我们就先从线程开刀。

    Pthreads && NSThread

    先来看与线程有最直接关系的一套C的API:

    Pthreads

    POSIX线程(POSIX threads),简称Pthreads,是线程的POSIX标准。该标准定义了创建和操纵线程的一整套API。在类Unix操作系统(Unix、Linux、Mac OS X等)中,都使用Pthreads作为操作系统的线程。

    高大上有木有,跨平台有木有,你没用过有木有!下面我们来看一下这个看似牛逼但真的基本用不到的Pthreads是怎么用的:

    不如我们来用Pthreads创建一个线程去执行一个任务:

    记得引入头文件`#import "pthread.h"`

    -(void)pthreadsDoTask{

    /*

    pthread_t:线程指针

    pthread_attr_t:线程属性

    pthread_mutex_t:互斥对象

    pthread_mutexattr_t:互斥属性对象

    pthread_cond_t:条件变量

    pthread_condattr_t:条件属性对象

    pthread_key_t:线程数据键

    pthread_rwlock_t:读写锁

    //

    pthread_create():创建一个线程

    pthread_exit():终止当前线程

    pthread_cancel():中断另外一个线程的运行

    pthread_join():阻塞当前的线程,直到另外一个线程运行结束

    pthread_attr_init():初始化线程的属性

    pthread_attr_setdetachstate():设置脱离状态的属性(决定这个线程在终止时是否可以被结合)

    pthread_attr_getdetachstate():获取脱离状态的属性

    pthread_attr_destroy():删除线程的属性

    pthread_kill():向线程发送一个信号

    pthread_equal(): 对两个线程的线程标识号进行比较

    pthread_detach(): 分离线程

    pthread_self(): 查询线程自身线程标识号

    //

    *创建线程

    int pthread_create(pthread_t _Nullable * _Nonnull __restrict, //指向新建线程标识符的指针

    const pthread_attr_t * _Nullable __restrict,  //设置线程属性。默认值NULL。

    void * _Nullable (* _Nonnull)(void * _Nullable),  //该线程运行函数的地址

    void * _Nullable __restrict);  //运行函数所需的参数

    *返回值:

    *若线程创建成功,则返回0

    *若线程创建失败,则返回出错编号

    */

    //

    pthread_t thread = NULL;

    NSString *params = @"Hello World";

    int result = pthread_create(&thread, NULL, threadTask, (__bridge void *)(params));

    result == 0 ? NSLog(@"creat thread success") : NSLog(@"creat thread failure");

    //设置子线程的状态设置为detached,则该线程运行结束后会自动释放所有资源

    pthread_detach(thread);

    }

    void *threadTask(void *params) {

    NSLog(@"%@ - %@", [NSThread currentThread], (__bridge NSString *)(params));

    returnNULL;

    }

    输出结果:

    1、ThreadDemo[1197:143578] creat thread success

    2、ThreadDemo[1197:143649] {number = 3, name = (null)} - Hello World

    从打印结果来看,该任务是在新开辟的线程中执行的,但是感觉用起来超不友好,很多东西需要自己管理,单单是任务队列以及线程生命周期的管理就够你头疼的,那你写出的代码还能是艺术么!其实之所以抛弃这套API很少用,是因为我们有更好的选择:NSThread。

    NSThread

    哎呀,它面向对象,再去看看苹果提供的API,对比一下Pthreads,简单明了,人生仿佛又充满了阳光和希望,我们先来一看一下系统提供给我们的API自然就知道怎么用了,来来来,我给你注释一下啊:

    @interface NSThread : NSObject

    //当前线程

    @property (class, readonly, strong) NSThread *currentThread;

    //使用类方法创建线程执行任务

    + (void)detachNewThreadWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

    + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;

    //判断当前是否为多线程

    + (BOOL)isMultiThreaded;

    //指定线程的线程参数,例如设置当前线程的断言处理器。

    @property (readonly, retain) NSMutableDictionary *threadDictionary;

    //当前线程暂停到某个时间

    + (void)sleepUntilDate:(NSDate *)date;

    //当前线程暂停一段时间

    + (void)sleepForTimeInterval:(NSTimeInterval)ti;

    //退出当前线程

    + (void)exit;

    //当前线程优先级

    + (double)threadPriority;

    //设置当前线程优先级

    + (BOOL)setThreadPriority:(double)p;

    //指定线程对象优先级 0.0~1.0,默认值为0.5

    @property double threadPriority NS_AVAILABLE(10_6, 4_0);

    //服务质量

    @property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);

    //线程名称

    @property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0);

    //栈区大小

    @property NSUInteger stackSize NS_AVAILABLE(10_5, 2_0);

    //是否为主线程

    @property (class, readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0);

    //获取主线程

    @property (class, readonly, strong) NSThread *mainThread NS_AVAILABLE(10_5, 2_0);

    //初始化

    - (instancetype)init NS_AVAILABLE(10_5, 2_0) NS_DESIGNATED_INITIALIZER;

    //实例方法初始化,需要再调用start方法

    - (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument NS_AVAILABLE(10_5, 2_0);

    - (instancetype)initWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

    //线程状态,正在执行

    @property (readonly, getter=isExecuting) BOOL executing NS_AVAILABLE(10_5, 2_0);

    //线程状态,正在完成

    @property (readonly, getter=isFinished) BOOL finished NS_AVAILABLE(10_5, 2_0);

    //线程状态,已经取消

    @property (readonly, getter=isCancelled) BOOL cancelled NS_AVAILABLE(10_5, 2_0);

    //取消,仅仅改变线程状态,并不能像exist一样真正的终止线程

    - (void)cancel NS_AVAILABLE(10_5, 2_0);

    //开始

    - (void)start NS_AVAILABLE(10_5, 2_0);

    //线程需要执行的代码,一般写子类的时候会用到

    - (void)main NS_AVAILABLE(10_5, 2_0);

    @end

    另外,还有一个NSObject的分类,瞅一眼:

    @interface NSObject (NSThreadPerformAdditions)

    //隐式的创建并启动线程,并在指定的线程(主线程或子线程)上执行方法。

    - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray *)array;

    - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;

    - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray *)array NS_AVAILABLE(10_5, 2_0);

    - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);

    - (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg NS_AVAILABLE(10_5, 2_0);

    @end

    上面的介绍您还满意吗?小的帮您下载一张图片,您瞧好:

    -(void)creatBigImageView{

    self.bigImageView = [[UIImageView alloc] initWithFrame:self.view.bounds];

    [self.view addSubview:_bigImageView];

    UIButton *startButton = [UIButton buttonWithType:UIButtonTypeSystem];

    startButton.frame = CGRectMake(0, 0, self.view.frame.size.width / 2, 50);

    startButton.backgroundColor = [UIColor grayColor];

    [startButton setTitle:@"开始加载" forState:UIControlStateNormal];

    [startButton addTarget:self action:@selector(loadImage) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:startButton];

    UIButton *jamButton = [UIButton buttonWithType:UIButtonTypeSystem];

    jamButton.frame = CGRectMake(self.view.frame.size.width / 2, 0, self.view.frame.size.width / 2, 50);

    jamButton.backgroundColor = [UIColor grayColor];

    [jamButton setTitle:@"阻塞测试" forState:UIControlStateNormal];

    [jamButton addTarget:self action:@selector(jamTest) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:jamButton];

    }

    -(void)jamTest{

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"线程阻塞" message:@"" delegate:nil cancelButtonTitle:@"好" otherButtonTitles:nil, nil];

    [alertView show];

    }

    -(void)loadImage{

    NSURL *imageUrl = [NSURL URLWithString:@"http://img5.duitang.com/uploads/item/201206/06/20120606174422_LZSeE.thumb.700_0.jpeg"];

    NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];

    [self updateImageData:imageData];

    }

    -(void)updateImageData:(NSData*)imageData{

    UIImage *image = [UIImage imageWithData:imageData];

    self.bigImageView.image = image;

    }

    相关文章

      网友评论

          本文标题:线程

          本文链接:https://www.haomeiwen.com/subject/hxllsxtx.html