iOS多线程-pthread&NSThread

242 阅读4分钟

回顾函数指针

/*
 函数指针:函数的指针,本质上是一个指针,指向函数的指针
 指针函数:指针的函数,代表函数的值是一个指针类型
 
 C函数语法:
        返回值类型 函数名(参数列表){
            函数体;
        }
 */
        void test(){
            NSLog(@"...");
        }
 /*
 函数指针的语法:
        返回值类型  (*函数名)(参数列表)
 */
    	void (*p)();  //这是一个指针变量,变量名为p,指向的是无参无返回值的函数
    	int (*p2)();   //这是一个指针变量,变量名为p2,指向的是无参有int类型返回值的函数
    	int (*p3)(int num); //这是一个指针变量,变量名为p3,指向的是一个有int类型参数和int类型返回值的函数
 /*
 怎么给函数指针赋值??
        p = 函数名;   因为函数名就是函数地址
 */
        p = test;
 
 //void* 其实是C语言中的万能指针,相当于OC中的id

pthread的使用

  • pthread开辟子线程
    • 使用pthread之前,必须导入头文件#import <pthread.h>
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //NSLog(@"点击里,创建前%@",[NSThread currentThread]);
    //[self demo];
    
    //C语言中以_t或者_ref结尾的都是C语言中的类型
    pthread_t p;
  
    NSString *str = @"abc";
    
    //参数1:指向这个子线程的指针对象,要加取地址符,如果传入&p,代表这个线程由p指向了,换句话说就是通过p能找到这个子线程
    //参数2:线程的属性(可以配置线程占用内存大小之类的,一般NULL就行)
    //参数3:函数名(需要这个线程去执行的函数)
    //参数4:函数的参数,没有参数就传NULL
    //参数3和4的意思就是指:子线程执行哪个函数里面的代码并且给这个函数传入什么参数
    int res = pthread_create(&p, NULL,test, (__bridge void *)(str));
    //桥接:桥梁,把两种类型沟通起来
    //为什么要这样?因为OC的对象目前在ARC下都是由系统管理负责回收
    //但是C对象不是由系统管理的,所以把OC转C对象时,需要做桥接
    //意思是告诉系统,这个对象转成C以后也由系统来管理
    
    //返回值是int类型,代表线程是否创建成功
    //返回0代表成功,返回其他代表失败
    //返回值其实是一个错误标识,只有0代表没有错误,如果为其他数字代表不同的错误
    //比如1代表xxx错误,比如2代表yyy错误
    if(res == 0){
        NSLog(@"创建成功");
    }else{
        NSLog(@"创建失败");
    }
    //NSLog(@"点击里,创建后%@",[NSThread currentThread]);
}

void *test(void *num){
    NSString *str = (__bridge NSString *)(num);
    
    //NSLog(@"%p",num);
//    NSLog(@"test里%@",[NSThread currentThread]);
    
    NSLog(@"%@",str);
    
    return NULL;
}

-(void)demo{
    //[NSThread currentThread]可以打印出当前线程对象的信息
    //也就是可以看到当前代码是由哪个线程执行的
    /*
      是不是主线程看number,number==1才是主线程,number!=1是子线程
    */
    NSLog(@"demo方法%@",[NSThread currentThread]);
}

NSThread的使用

三种创建方式

  1. 构造方法方式

    //NSThread 是一个线程对象
    //参数1和参数2:开启的子线程要调用哪个对象的哪个方法
    //参数3:给这个方法的参数,有就传没有就传nil
    NSThread *th1 = [[NSThread alloc] initWithTarget:self selector:@selector(demo:) object:@"hello"];
    
    //用这种方式创建,一定要start
    [th1 start];
    

    PS:需要start !!!
    可以在线程执行的方法外也访问到这个线程对象

  2. 类方法方式

    //参数1:哪个方法
    //参数2:哪个对象的
    //参数3:方法的参数
    //这个方法会创建一个新的线程来执行某个的对象的某个方法
    [NSThread detachNewThreadSelector:@selector(demo:) toTarget:self withObject:@"hello"];
    

    不需要start
    在调用的方法外访问不到线程对象

  3. 分类方式(NSObject的分类)

    //参数1:调用哪个方法
    //参数2:方法的参数
    [self performSelectorInBackground:@selector(demo:) withObject:@"abc"];
    

    也不需要start
    调用的方法外访问不到线程对象

常用属性

  • name(线程名称)
  • stackSize(栈区大小)
    • 默认情况下,无论是主线程还是子线程,栈区大小都是 512K(设置比512小的值无效)
    • 栈区大小可以设置 [NSThread currentThread].stackSize = 1024 * 1024;
    • 必须是 4KB 的倍数
  • isMainTread(是否主线程)
  • threadPriority(线程优先级)
    • 优先级,是一个浮点数,取值范围从 0~1.0
    • 1.0最高,0.0最低
    • 默认优先级是 0.5
    • 优先级高只是保证 CPU 调度的可能性会高,不是先调用完成优先级高的进程
  • qualityOfService(服务质量-iOS8.0推出)
    • NSQualityOfServiceUserInteractive - 用户交互,例如绘图或者处理用户事件
    • NSQualityOfServiceUserInitiated - 用户需要
    • NSQualityOfServiceUtility - 实用工具,用户不需要立即得到结果
    • NSQualityOfServiceBackground - 后台
    • NSQualityOfServiceDefault - 默认,介于用户需要和实用工具之间