iOS多线程之GCD
GCD的概念
GCD(Grand Central Dispatch),是有Apple公司开发的一个多核编程的解决方案,用以优化应用程序支持多核处理器,是基于线程模式之上执行并发任务。
GCD的优点
1.利用设备多核进行并行运算
2.GCD自动充分使用设备的CPU内核
3.GCD自动管理线程的生命周期(线程创建、线程调度、线程销毁)
4.使用简单
GCD任务和队列
任务:就是执行操作,即可以执行的代码;执行任务有两种方式:同步 和 异步。
- 同步(sync):
阻塞线程: 同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行;
不可以开辟新的线程 - 异步(async):
不会阻塞线程:异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务
可以开辟新的线程
队列:Dispatch Queue
指执行任务的等待队列,即用来存放任务的队列。队列是一种特殊的线性表,遵循 FIFO(先进先出)的原则,即新任务总是被插入到队列的末尾,而读取任务的时候总是从队列的头部开始读取。每读取一个任务,则从队列中释放一个任务;
在 GCD 中有两种队列:串行队列 和 并发队列。两者都符合 FIFO(先进先出)的原则。两者的主要区别是:执行顺序不同,以及开启线程数不同。
串行队列(Serial Dispatch Queue): 每次只有一个任务被执行。让任务一个接着一个地执行
并发队列(Concurrent Dispatch Queue): 可以让多个任务同时执行。(可以开启多个线程,并且同时执行任务)
GCD 的使用步骤
GCD的使用分为两步:
1. 创建队列
2. 将任务追加到队列中
创建队列
创建队列使用dispatch_queue_create
函数
/*创建队列label:队列的唯一标识符attr:用来识别是串行队列还是并发队列;DISPATCH_QUEUE_SERIAL 表示串行队列;DISPATCH_QUEUE_CONCURRENT 表示并发队列;dispatch_queue_tdispatch_queue_create(const char *_Nullable label,dispatch_queue_attr_t _Nullable attr);*/dispatch_queue_t queue = dispatch_queue_create("qctt", DISPATCH_QUEUE_SERIAL);
获取队列
串行队列,GCD 默认提供了主队列(Main Dispatch Queue)
//获取主队列dispatch_queue_t mainqueue = dispatch_get_main_queue();
并发队列,GCD 默认提供了全局并发队列(Global Dispatch Queue)
/**参数一表示队列优先级,默认 DISPATCH_QUEUE_PRIORITY_DEFAULTDISPATCH_QUEUE_PRIORITY_DEFAULTDISPATCH_QUEUE_PRIORITY_HIGHDISPATCH_QUEUE_PRIORITY_DEFAULTDISPATCH_QUEUE_PRIORITY_LOWDISPATCH_QUEUE_PRIORITY_BACKGROUND参数二暂时没用,用 0 即可*/dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
创建任务
GCD提供了创建同步任务以及异步任务的函数;
同步任务: dispatch_sync
// 同步执行任务创建方法dispatch_sync(dispatch_get_global_queue(0, 0), ^{NSLog(@"%s",__func__);});
异步任务: dispatch_async
// 异步执行任务创建方法dispatch_async(dispatch_get_global_queue(0, 0), ^{NSLog(@"%s",__func__);});
任务和队列不同组合方式的区别
区别 | 串行队列 | 并发队列 | 主队列 |
---|---|---|---|
sync | 没有开启新线程,串行 | 没有开启新线程,串行 | 死锁卡住不执行 |
async | 开启新线程,串行 | 开启新线程,并发 | 没有开启新线程,串行 |
GCD 的组合使用
串行队列 + 同步执行
不会开启新线程,在当前线程执行任务。执行完一个任务,再执行下一个任务。
/*** 串行队列 + 同步执行* 特点:不会开启新线程,在当前线程执行任务。执行完一个任务,再执行下一个任务。*/dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_SERIAL);dispatch_sync(queue, ^{// 追加任务 1[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程});dispatch_sync(queue, ^{// 追加任务 2[NSThread sleepForTimeInterval:3]; // 模拟耗时操作NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程});dispatch_sync(queue, ^{// 追加任务 3[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程});NSLog(@"syncSerial---end");
运行结果同步顺序执行
串行队列 + 异步执行
会开启新线程。执行完一个任务,再执行下一个任务。
/*** 串行队列 + 异步执行* 特点:会开启新线程。执行完一个任务,再执行下一个任务。*/dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);dispatch_async(queue, ^{// 任务 1[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程});dispatch_async(queue, ^{// 任务 2[NSThread sleepForTimeInterval:3]; // 模拟耗时操作NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程});dispatch_async(queue, ^{// 任务 3[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程});NSLog(@"asyncSerial---end");
打印日志:
2022-05-31 10:20:28.125523+0800 DemoTest2022[5271:199261] asyncSerial---end
2022-05-31 10:20:29.125730+0800 DemoTest2022[5271:199349] 1---<NSThread: 0x600003d8fb80>{number = 5, name = (null)}
2022-05-31 10:20:32.131137+0800 DemoTest2022[5271:199349] 2---<NSThread: 0x600003d8fb80>{number = 5, name = (null)}
2022-05-31 10:20:34.132492+0800 DemoTest2022[5271:199349] 3---<NSThread: 0x600003d8fb80>{number = 5, name = (null)}
并发队列 + 同步执行
不会开启新线程,在当前线程执行任务。执行完一个任务,再执行下一个任务。
/*** 并发队列 + 同步执行* 特点:在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。*/dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);dispatch_sync(queue, ^{// 任务 1[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程});dispatch_sync(queue, ^{// 任务 2[NSThread sleepForTimeInterval:3]; // 模拟耗时操作NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程});dispatch_sync(queue, ^{// 任务 3[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程});NSLog(@"syncConcurrent---end");
2022-05-31 10:31:42.719133+0800 DemoTest2022[5476:209855] 1---<_NSMainThread: 0x6000032507c0>{number = 1, name = main}
2022-05-31 10:31:45.719679+0800 DemoTest2022[5476:209855] 2---<_NSMainThread: 0x6000032507c0>{number = 1, name = main}
2022-05-31 10:31:46.720250+0800 DemoTest2022[5476:209855] 3---<_NSMainThread: 0x6000032507c0>{number = 1, name = main}
2022-05-31 10:31:46.720599+0800 DemoTest2022[5476:209855] syncConcurrent---end
并发队列 + 异步执行
可以开启多个线程,任务同时执行。
/*** 并发队列 + 异步执行* 特点:可以开启多个线程,任务同时执行。*/dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue, ^{// 任务 1[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程});dispatch_async(queue, ^{// 任务 2[NSThread sleepForTimeInterval:3]; // 模拟耗时操作NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程});dispatch_async(queue, ^{// 任务 3[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程});NSLog(@"asyncConcurrent---end");
执行结果:
2022-05-31 10:27:26.350321+0800 DemoTest2022[5398:206005] asyncConcurrent---end
2022-05-31 10:27:27.351422+0800 DemoTest2022[5398:206201] 3---<NSThread: 0x600002d22dc0>{number = 4, name = (null)}
2022-05-31 10:27:28.354696+0800 DemoTest2022[5398:206202] 1---<NSThread: 0x600002d3c7c0>{number = 6, name = (null)}
2022-05-31 10:27:29.352304+0800 DemoTest2022[5398:206200] 2---<NSThread: 0x600002d34e00>{number = 9, name = (null)}
GCD 的其他方法栅栏函数
GCD栅栏方法: dispatch_barrier_async
dispatch_barrier_async
方法会等待前边追加到并发队列中的任务全部执行完毕之后,再将指定的任务追加到该异步队列中。然后在 dispatch_barrier_async
方法追加的任务执行完毕之后,异步队列才恢复为一般动作,接着追加任务到该异步队列并开始执行。
void
dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
/*** 栅栏方法 dispatch_barrier_async*/dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue, ^{// 追加任务 1[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程});dispatch_async(queue, ^{// 追加任务 2[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程});dispatch_barrier_async(queue, ^{// 追加任务 barrier[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"barrier---%@",[NSThread currentThread]);// 打印当前线程});dispatch_async(queue, ^{// 追加任务 3[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程});dispatch_async(queue, ^{// 追加任务 4[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"4---%@",[NSThread currentThread]); // 打印当前线程});
执行日志:先执行栅栏之前的21,然后执行栅栏,再添加后续任务并执行
2022-05-31 10:48:48.606711+0800 DemoTest2022[5722:224160] 2---<NSThread: 0x600002b12b80>{number = 8, name = (null)}
2022-05-31 10:48:49.607101+0800 DemoTest2022[5722:224161] 1---<NSThread: 0x600002b05d00>{number = 5, name = (null)}
2022-05-31 10:48:51.608045+0800 DemoTest2022[5722:224161] barrier---<NSThread: 0x600002b05d00>{number = 5, name = (null)}
2022-05-31 10:48:52.609360+0800 DemoTest2022[5722:224161] 3---<NSThread: 0x600002b05d00>{number = 5, name = (null)}
2022-05-31 10:48:53.608776+0800 DemoTest2022[5722:224165] 4---<NSThread: 0x600002b0f900>{number = 7, name = (null)}
栅栏函数实现多读单写
#import "UserCenter.h"@interface UserCenter()
{// 定义一个并发队列dispatch_queue_t concurrent_queue;// 用户数据中心, 可能多个线程需要数据访问NSMutableDictionary *userCenterDic;
}@end// 多读单写模型
@implementation UserCenter- (id)init
{self = [super init];if (self) {// 通过宏定义 DISPATCH_QUEUE_CONCURRENT 创建一个并发队列concurrent_queue = dispatch_queue_create("read_write_queue", DISPATCH_QUEUE_CONCURRENT);// 创建数据容器userCenterDic = [NSMutableDictionary dictionary];}return self;
}- (id)objectForKey:(NSString *)key
{__block id obj;// 同步读取指定数据dispatch_sync(concurrent_queue, ^{obj = [userCenterDic objectForKey:key];});return obj;
}- (void)setObject:(id)obj forKey:(NSString *)key
{// 异步栅栏调用设置数据dispatch_barrier_async(concurrent_queue, ^{[userCenterDic setObject:obj forKey:key];});
}@end
GCD 延时执行方法:dispatch_after
dispatch_after
方法并不是在指定时间之后才开始执行处理,而是在指定时间之后将任务追加到主队列中。
/*** 延时执行方法 dispatch_after*/dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{// 2.0 秒后异步追加任务代码到主队列,并开始执行NSLog(@"after---%@",[NSThread currentThread]); // 打印当前线程});
}
GCD 执行一次:dispatch_once
在创建单例、或者有整个程序运行过程中只执行一次的代码时,我们就用到了 GCD 的 dispatch_once
方法。使用 dispatch_once
方法能保证某段代码在程序运行过程中只被执行 1 次,并且即使在多线程的环境下,dispatch_once
也可以保证线程安全。
void
dispatch_once(dispatch_once_t *predicate,DISPATCH_NOESCAPE dispatch_block_t block);
/*** 只执行一次 dispatch_once*/
static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{// 只执行 1 次的代码(这里面默认是线程安全的)
});
GCD 队列组:dispatch_group
场景:当需要异步执行多个耗时任务,然后执行完毕后回到主线程;
dispatch_group_notify
: 监听 group 中任务的完成状态,当所有的任务都执行完成后,追加任务到 group 中,并执行任务;dispatch_group_t group = dispatch_group_create();dispatch_queue_t global = dispatch_get_global_queue(0, 0);dispatch_group_async(group, global, ^{//添加任务[NSThread sleepForTimeInterval:2];NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程dispatch_async(global, ^{[NSThread sleepForTimeInterval:1];NSLog(@"11111---%@",[NSThread currentThread]);});});dispatch_group_async(group, global, ^{//添加任务[NSThread sleepForTimeInterval:1];NSLog(@"2---%@",[NSThread currentThread]);dispatch_async(global, ^{[NSThread sleepForTimeInterval:2];NSLog(@"222222---%@",[NSThread currentThread]);});});dispatch_group_notify(group, dispatch_get_main_queue(), ^{//等待 1,2 任务执行完成后到主线程执行3[NSThread sleepForTimeInterval:1];NSLog(@"3---%@",[NSThread currentThread]);NSLog(@"group end");});
2022-05-31 14:12:15.717237+0800 DemoTest2022[8494:370194] 2---<NSThread: 0x60000224d940>{number = 9, name = (null)}
2022-05-31 14:12:16.717106+0800 DemoTest2022[8494:370195] 1---<NSThread: 0x600002230980>{number = 4, name = (null)}
2022-05-31 14:12:17.718496+0800 DemoTest2022[8494:369922] 3---<_NSMainThread: 0x600002228ac0>{number = 1, name = main}
2022-05-31 14:12:17.718496+0800 DemoTest2022[8494:370195] 11111---<NSThread: 0x600002230980>{number = 4, name = (null)}
2022-05-31 14:12:17.718496+0800 DemoTest2022[8494:370194] 222222---<NSThread: 0x60000224d940>{number = 9, name = (null)}
2022-05-31 14:12:17.718751+0800 DemoTest2022[8494:369922] group enddispatch_group_wait
: 暂停当前线程(阻塞当前线程),等待指定的 group 中的任务执行完成后,才会往下继续执行dispatch_group_t group = dispatch_group_create();dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_group_async(group,queue , ^{// 追加任务 1[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程});dispatch_group_async(group, queue, ^{// 追加任务 2[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程});// 等待上面的任务全部完成后,会往下继续执行(会阻塞当前线程)dispatch_group_wait(group, DISPATCH_TIME_FOREVER);NSLog(@"group---end");
2022-05-31 14:36:09.722970+0800 DemoTest2022[8888:390059] 1---<NSThread: 0x6000027da3c0>{number = 3, name = (null)}
2022-05-31 14:36:09.722967+0800 DemoTest2022[8888:390062] 1---<NSThread: 0x6000027de940>{number = 7, name = (null)}
2022-05-31 14:36:09.723212+0800 DemoTest2022[8888:389913] group---enddispatch_group_enter
: 标志着一个任务追加到 group,执行一次,相当于 group 中未执行完毕任务数 +1;void dispatch_group_enter(dispatch_group_t group);
dispatch_group_leave
: 标志着一个任务离开了 group,执行一次,相当于 group 中未执行完毕任务数 -1;void dispatch_group_leave(dispatch_group_t group);
当 group 中未执行完毕任务数为0的时候,才会使
dispatch_group_wait
解除阻塞,以及执行追加到dispatch_group_notify
中的任务;/*** 队列组 dispatch_group_enter、dispatch_group_leave*/ - (void)groupEnterAndLeave {NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程NSLog(@"group---begin");dispatch_group_t group = dispatch_group_create();dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_group_enter(group);dispatch_async(queue, ^{// 追加任务 1[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程dispatch_group_leave(group);});dispatch_group_enter(group);dispatch_async(queue, ^{// 追加任务 2[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程dispatch_group_leave(group);});dispatch_group_notify(group, dispatch_get_main_queue(), ^{// 等前面的异步操作都执行完毕后,回到主线程.[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程NSLog(@"group---end");}); }
2022-05-31 14:56:53.413320+0800 DemoTest2022[9165:405241] currentThread---<_NSMainThread: 0x600001024500>{number = 1, name = main}
2022-05-31 14:56:53.413467+0800 DemoTest2022[9165:405241] group---begin
2022-05-31 14:56:55.415122+0800 DemoTest2022[9165:405400] 1---<NSThread: 0x60000102e080>{number = 6, name = (null)}
2022-05-31 14:56:55.415122+0800 DemoTest2022[9165:405398] 2---<NSThread: 0x600001078040>{number = 8, name = (null)}
2022-05-31 14:56:57.415797+0800 DemoTest2022[9165:405241] 3---<_NSMainThread: 0x600001024500>{number = 1, name = main}
2022-05-31 14:56:57.416083+0800 DemoTest2022[9165:405241] group---end
GCD 信号量:dispatch_semaphore
信号量是基于计数器的一种多线程同步机制,用来管理对资源的并发访问。
GCD 中的信号量是指持有计数的信号。在 Dispatch Semaphore 中,使用计数来完成这个功能,信号量为0则阻塞线程,大于0则不会阻塞。则我们通过改变信号量的值,来控制是否阻塞线程,从而达到线程同步。
Dispatch Semaphore 提供了三个方法:
dispatch_semaphore_create
:创建一个 Semaphore 并初始化信号的总量dispatch_semaphore_signal
:发送一个信号,让信号总量加 1dispatch_semaphore_wait
:可以使总信号量减 1,信号总量小于 0 时就会一直等待(阻塞所在线程),否则就可以正常执行。
信号量dispatch_semaphore
主要用于两个方面:保持线程同步、为线程加锁
- 保持线程同步
/** 以AFNetworking源码为例*/
- 为线程加锁
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);for (int i = 0; i < 10; i++) {dispatch_async(queue, ^{// 相当于加锁 -1操作dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);/*todo:*/// 相当于解锁 +1操作。 计数器>= 0就不阻塞线程int t = rand()%3;//随机0-3秒休眠耗时操作[NSThread sleepForTimeInterval:t];NSLog(@"%d",i);dispatch_semaphore_signal(semaphore);});}
2022-05-31 17:18:02.966335+0800 DemoTest2022[11107:503565] 0
2022-05-31 17:18:03.970640+0800 DemoTest2022[11107:503570] 1
2022-05-31 17:18:05.972503+0800 DemoTest2022[11107:503564] 2
2022-05-31 17:18:07.976567+0800 DemoTest2022[11107:503566] 3
2022-05-31 17:18:08.980964+0800 DemoTest2022[11107:503569] 4
2022-05-31 17:18:10.984335+0800 DemoTest2022[11107:503568] 5
2022-05-31 17:18:10.984578+0800 DemoTest2022[11107:503572] 6
2022-05-31 17:18:12.985732+0800 DemoTest2022[11107:503573] 7
2022-05-31 17:18:14.991233+0800 DemoTest2022[11107:503574] 8
2022-05-31 17:18:15.995794+0800 DemoTest2022[11107:503575] 9
iOS多线程之GCD相关推荐
- iOS多线程之GCD小记
iOS多线程之GCD小记 iOS多线程方案简介 从各种资料中了解到,iOS中目前有4套多线程的方案,分别是下列4中: 1.Pthreads 这是一套可以在很多操作系统上通用的多线程API,是基于C语言 ...
- (五十五)iOS多线程之GCD
GCD的全称为Grand Central Dispatch,翻译为大中央调度,是Apple开发的一个多线程编程解决方法. 进程和线程的概念: 正在进行中的程序被称为进程,负责程序运行的内存分配,每一个 ...
- IOS中的多线程之GCD
在ios中,使用多线程有三种方式,分别是:NSThread.NSOperation和NSOperationQueue.GCD,在本节,主要讲解一下CDD的使用. GCD(Grand Central D ...
- iOS 线程之GCD的高级使用方法
之前的一篇关于线程的blog已经为大家介绍了GCD的简单使用方式及样例说明,今天因为项目中有特殊的应用GCD的实例,为大家介绍两种特殊需求的使用GCD的方法. 目的:实现一件事情做完,再做下一件事情. ...
- IOS多线程之Block编程
1 什么是block iOS SDK 4.0開始,Apple引入了block这一特性.字面上说,block就是一个代码块.可是它的奇妙之处在于在内联(inline)运行的时候(这和C++非常像)还能够 ...
- iOS多线程之7.NSOperation的初识
NSOperation和GCD一样,不用我们管理线程的生命周期,加锁等问题,只要把操作封装进NSOperation中,系统会自动帮我们创建线程,执行操作.而且他是面向对象的,我们看起来更容易理解,使用 ...
- (五十六)iOS多线程之NSOperation
NSOpertation是一套OC的API,是对GCD进行的Cocoa抽象. NSOperation有两种不同类型的队列,主队列和自定义队列. 主队列运行于主线程上,自定义队列在后台运行. [NSBl ...
- 关于多线程之GCD的一些学习要点
GCD是当前多线程使用最方便的,也是使用比较多的. 学习GCD主要集中在一下几点: 一.队列,同步,异步 1.主队列:dispatch_get_main_queue(); 2.串行队列:dispatc ...
- ios多线程之NSThread头文件详解
1.NSThread 头文件中的相关方法 //获取当前线程+(NSThread *)currentThread; //创建线程后自动启动线程 + (void)detachNewThreadSelect ...
- linux 线程pthread_detach,linux线程之pthread_join和pthread_detach
在任何一个时间点上,线程是可结合的(joinable)或者是分离的(detached).一个可结合的线程能够被其他线程收回其资源和杀死.在 被其他线程回收之前,它的存储器资源(例如栈)是不释放的.相反 ...
最新文章
- Maven的生命周期和maven-assembly-plugin插件使用
- 万变不离其宗之海量数据下的算法问题处理思路
- 图形—9patch,shape ,selector
- TreeView无限极分类绑定(从数据库读取数据源)
- 让linux的SSH客户端也能记住服务器的密码
- 快递员遭投诉吞安眠药护自尊 顺丰王卫:马上检讨 立即整改
- java多条件不定条件查询
- Atitit.request http乱码的设计防止 检测与解决最近实践p825 attilax总结.doc
- 微信小程序的剪贴板 +复制剪贴,在淘宝中打开就可以获取到商品
- 计算机房防凝露保温材料,机房保温的方案.docx
- 银企直连ukey 集中管理方案
- java 游戏源码_源码下载 - Java源码 - 游戏娱乐
- 计算机二级ppt文小雨,计算机二级PPT真题:制作日月潭介绍PPT
- 虚拟机内linux网络连接,vmware中redhat5虚拟机无法连接网络
- 数字黑洞java_java实现数字黑洞
- sping循环依赖:but has eventually been wrapped. This means that said other beans do not use the final
- Axure计算器原型
- 从头来过教你PHP脚本语言(先导篇)
- cdn连接失败是什么意思_CDN经常连接失败的原因有哪些?
- 全新安装Windows10系统(PE下)