多线程 NSTread

1.耗时操作
MARk - 耗时操作

[NSTread currenThread]:当前线程
通常用来开发调试过程中 可以用来判断是否是主线程

number = 1 就是主线程
number != 1 就是子线程 不要纠结数字,只要不是1 就是子线程 具体数组,程序员不能决定
代码:
耗时的操作:
- (void)longOperatiion {
   
 for (int i = 0; i < 10; ++i) {
       
 // 提示:NSLog的性能非常差!在发布应用程序的时候,要把NSLog过滤掉
       
 NSLog(@"%@ %@", @(i), [NSThread currentThread]);
    }
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//    [self longOperatiion];
   
 // 在后台执行耗时操作
    [
self performSelectorInBackground:@selector(longOperatiion) withObject:nil];
}


2.pthred 演练
  pthread_t threadId = NULL;
   
   
 // 准备参数
   
 id str = @"hello thread";
   
   
 int result = pthread_create(&threadId, NULL, demo, (__bridge void *)(str));
   
   
 if (result) {
       
 NSLog(@"线程创建失败 %d", result);
    }
 else {
       
 NSLog(@"OK");
    }
}

// 线程要调用执行的函数
// [NSThread currentThread] 可以在所有的多线程技术中使用!
// 查看当前代码执行所在的线程
void * demo (void * param) {

   
 NSString *str = (__bridge NSString *)(param);
   
   
 NSLog(@"%@ --- %@", [NSThread currentThread], str);
   
   
 return NULL;
}

返回值:
- 线程创建成功 则返回 0
- 线程创建失败 则返回出错误编号

* 成功的原因只要一个,失败的原因可以有很多 在很多C语言中都会使用这个套路!

参数:
1> 第一个参数为执行线程标示符的指针
   1)在C语言框架中,没有对象的概念,对象是通过结构体来实现的
   2)通常”对象”的类型 会以_t/Ref 结尾
   3)定义的时候 不需要使用*
2> 第二个参数用来设置线程的属性
3> 第三个参数是线程运行”函数”的”起始地址"

   vid*(*)(void *)
   * block 匿名的函数指针
   * 定义返回值(^)(参数)

在C 语言 的void* 和oc 的id 是等于的
id (函数名激素hi指向函数起始位置的地址 的别名)(id)
*数组名: 指向数组第一个元素的地址

4> 最后一个参数是运行的参数

 关于 __bridge — 桥接

内存管理概念:
特点:
1> 编译器在编译代码的时候,会根据 “oc”代码的结构,自动添加retain/relesse/autorelses

2>ARC只负责 OC部分的代码 不负责C/C++ 语言部分代码

3>如果开发的时候,涉及到混合语言开发,,如果使用C语言函数,出现create/copy/tetain/new 等子项 大多数需要程序员手动relese 否则出现内存泄露问题

4>在混合开发的时候 如果涉及到c框架和OC框架之间传递参数,需要使用”桥接”告诉编译器如如何管理内存
__bridge 就是保存原有的管理方法

5>提问MRC 中需要桥接嘛??/不需要,MRC中所有的内存都市程序员负责的

6>提问:管理内存,管理的是哪一区的内存,堆区 特点 :alloc/copy/ration 等等的函数都市和堆区有关的

三:创建线程(NSThread)的三种办法
第一种
  // 实例化一个 NSThread 对象
   
 NSThread *t1 = [[NSThread alloc] initWithTarget:selfselector:@selector(longOperation:) object:@"NSThread"];
   
   
 // 启动线程
    [t1 start];
第二种 类方法,分离detach
 // detach > "分离"
   
 // 直接新建线程,并且执行 @selector 方法
    [NSThread detachNewThreadSelector:@selector(longOperation:) toTarget:selfwithObject:dic];
第三种方法 per
是NSObject 的一个分类方法
是 thread 的字眼 却是可以开启后台线程 执行selector方法
因数的多线程方法 类方法类似 可以直接开启线程执行方法
[self performSelectorInBackground:@selector(longOperation:) withObject:@"perform"];

四.线程的状态

  // 1. 实例化一个线程对象(新建)
   
 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run)object:nil];
   
   
 // 2. 启动线程(就绪,线程对象会被添加到可调度线程池,等待 CPU 调度)
    [thread
 start];
}
 在后台执行的方法
 */

- (
void)run {
   
   
 // 如果满足某一个条件,可以让线程进入"阻塞"状态
   
 // 休眠 - 让当前线程休眠
   
 NSLog(@"睡会");
   
 // 从现在开始睡几秒
    [
NSThread sleepForTimeInterval:1.0];
   
   
 for (int i = 0; i < 20; ++i) {
       
       
 // 有可能满足另外一个条件后,再次进入休眠状态
       
 if (i == 8) {
           
 NSLog(@"再睡会");
           
 // 睡到指定的日期 - 从现在开始间隔 2 
            [
NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
        }
       
       
 NSLog(@"%@ %d", [NSThread currentThread], i);
       
       
 CGMutablePathRef path = CGPathCreateMutable();
       
       
 // 死亡  满足某一个条件后,退出当前所在线程
       
 // 一旦退出了当前线程,后续的所有代码都不会执行!
       
 if (i == 12) {
           
 // Invoking this method should be avoided as it does not give your thread a chance to clean up any resources it allocated during its execution.
           
 // 调用此方法,需要注意,此方法不会给任何机会去清理线程执行过程中分配的资源
           
 // 注意:如果使用了 C 语言框架,尤其做了分配对象的工作,需要注意在何时的位置增加 release
           
 CGPathRelease(path);
           
            [
NSThread exit];
        }
       
       
 CGPathRelease(path);
    }
   
   
 NSLog(@"结束了!");
}

六.原子属性
nonatomic 飞原子属性
atomic    原子属性 是默认属性
       * 是在多线程开发是,抱着多个线程的写入的时候,能够保证只有一条线程执行写入操作
       * 是一个单(线程)写多(线程)读的多线程技术
       * 原子属性 解决不了卖票问题,因为卖票的读写都需要锁定
       * 有可能会出现”脏数据"重新读书一下就可以了
      
       * 原子属性内部也有一把锁
       * 原子属性的锁的性能比互斥锁高
自旋锁 & 互斥锁
共同点:
   都市保证同一时间,只有一条线程能够执行锁定范围的代码
区别:
   互斥锁:如果发现代码已经被(其他线程)锁定,当前线程会进入休眠状态,等锁解除之后,重新被唤醒
   想当于出了可调度缓冲池
   自旋锁:如果发现代码已经被(其他线程)锁定 当前线程会进入死循环的方法,一直判断是否解除,一旦解除立即执行,       适合锁定非常短的代码,能够保持更高的执行性能,不会离开可调度缓冲池

提示:互斥锁在开发中,要尽量少用,性能很差
结论:只要用到锁,性能都高不了

*线程安全

如果一个属性,在多个线程执行的情况下,仍然能够保证得到正确的结果,就叫做线程安全

要实现线程安全,就必须要使用”锁”->性能不好!

UI 线程 -> 约定: 主线程,所有UI更新,都需要在主线程上执行

原因:UIKit不是线程安全,就是为了更高的性能
取舍!!!!!

-----------------------------------------------------------------------------------------------------------------------------------------------------

模拟原子属性的实现 - 如果重写了原子属性的setter方法,想当于覆盖了系统提供的setter方法
此时系统要求,必须重写getter方法
定义属性是,系统默认提供getter&setter方法 并且生成一个 _成员变量
但是如果自己重写了getter & setter 方法 _成员变量不会自己生成

@synthesize 合成指令 可以指令保存属性数值的成员变量
现在这个方法太古老了,遇到的代码不要看了
@synthesize  obj2 = _obj2;

- (
void)setObj2:(NSObject *)obj2 {
   
 // 使用互斥锁
   
 @synchronized(self) {
       
 _obj2 = obj2;
    }
}

- (
NSObject *)obj2 {
   
 return _obj2;
}

- (
void)viewDidLoad {
    [
super viewDidLoad];
   
   
 NSData *data = nil;
   
 // 写入文件的原子性!先写入到一个临时文件,所有写入完成后,再一次写入目标文件!
   
 // 能够对文件的写入进行保护
//    [data writeToFile:@"path" atomically:YES];
}

// 测试自旋锁&互斥锁的效率!
- (
void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
   
 long largeNumber = 1000 * 1000;
   
   
 // 自旋锁
   
 // 2001-01-01 00:00:00 到现在的秒数
   
 CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
   
   
 for (long i = 0; i < largeNumber; ++i) {
       
 self.obj3 = [[NSObject alloc] init];
    }
   
   
 CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
   
 NSLog(@"自旋锁 %f", end - start);
   
   
 // 互斥锁
   
 // 2001-01-01 00:00:00 到现在的秒数
    start =
 CFAbsoluteTimeGetCurrent();
   
   
 for (long i = 0; i < largeNumber; ++i) {
       
 self.obj2 = [[NSObject alloc] init];
    }
   
    end =
 CFAbsoluteTimeGetCurrent();
   
 NSLog(@"互斥锁 %f", end - start);
}

七:线程的属性
提示:线程栈区大小都市512k 但是可以修改!!

在以前的ios办法,主线程栈区1m 子线程是512k 而且不能修改
 NSThread *t1 = [[NSThread alloc] initWithTarget:self selector:@selector(demo)object:nil];
   
   
 // 线程的名称,通常在"大的商业应用"中,希望应用程序上架后,捕获到用户使用崩溃的一些场景
   
 // 如果知道程序是在哪一个线程中崩溃,能够辅助排查问题!
   
 // 如果线程非常多,而且在调试的时候,起到一定的辅助作用!
    t1.name = @"Thread AAA";
- (void)demo {
   
 for (int i = 0; i < 10; ++i) {
       
 // %tu 是可以针对不同的 CPU 架构,自动调整 无符号整数的长度 NSUInteger
       
 // %zd 是可以针对不同的 CPU 架构,自动调整 有符号整数的长度 NSInteger
       
 NSLog(@"%@ %d %tuK", [NSThread currentThread], i, [NSThreadcurrentThread].stackSize / 1024);
    }

The thread’s priority, which is specified by a floating point number from 0.0 to 1.0, where 1.0 is highest priority.
线程的优先级,取值范围  0~1.0 1.0  的优先级最高
“typical” thread priority might be 0.5
默认的线程优先级是  0.5
t1.threadPriority = 0;

优先级搞只能说明cpu在调度的时候,会优先去调度,并不意味着,优先极地的就不被调度

在多线程开发的时候,有几点提示:

1.在ios开发中,多线程的最主要的母的:就是把耗时的操作放在后台运行
//从现在开始的描述
   CFAbsoluteTime  start =  CFAbsoluteTimeGetCurrent ();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值