当前位置:首页 > 科技数码 > 正文

GCD 线程安全同步

摘要: GCD线程安全同步最佳答案53678位专家为你答疑解惑GCD线程安全同步-信号量GCD线程安全同步学习、记录与分享GCD与NST...

GCD 线程安全同步

最佳答案 53678位专家为你答疑解惑

GCD 线程安全同步-信号量

GCD 线程安全同步学习、记录与分享GCD 与 NSThread比较GCD会自动利用更多的CPU内核、 会自动管理线程的生命周期 (创建线程、调度线程、销毁线程)开发者只需用GCD函数创建任务,加入队列,GCD会根据CPU内核自动创建线程(创建多少,怎么创建不许要管)去完成任务。NSThread需要开发者自己创建线程去完成任务。GCD核心函数:异步和同步任务:创建任务队列:将任务加入队列(串行队列、并发队列)队列

并发队列

队列里的任务会自动开启多个线程并发执行,但是需要异步函数的任务才有效队列只是影响任务执行的方式,实际上并不能决定是否开启新的线程,仅仅是并发队列允许多个线程同时运行,而串行队列只能是一个一个任务在同一线程执行.创建并发队列
//通过直接创建的方式创建,参数决定是否是并发队列

//DISPATCH_QUEUE_CONCURRENT代表并发队列//DISPATCH_QUEUE_SERIAL或NULL代表串行队列//标示符代表这个队列的一个标记dispatch_queue_t qune=dispatch_queue_create("创建", DISPATCH_QUEUE_CONCURRENT);//通过获取全局队列来获得一个并发队列dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//这两个参数,第一个是优先级一般用默认,第二个直接设为0 是一个保留标记,实际作用不大

* 串行队列+ 队列里的任务会以串行的形式一个一个按顺序执行+ 创建串行队列

//直接创建//DISPATCH_QUEUE_SERIAL或NULL代表串行队列dispatch_queue_t queue=dispatch_queue_create("标示符", DISPATCH_QUEUE_SERIAL);//获得主队列,也是一种串行队列dispatch_queue_t queue=dispatch_get_main_queue();

#####函数* 同步函数:执行之后不立即返回,等待任务完成才返回,会阻塞当下线程

//queue代表你要放入的队列dispatch_sync(queue, ^{//在这里写要执行的代码});`

* 异步函数:执行之后立即返回,不会阻塞当下线程

//queue代表你要放入的队列dispatch_async(queue, ^{//在这里写要执行的代码});

* 栅栏函数

//隔断函数,前面执行完才会执行这个函数,这个函数执行完才会执行其他后面的函数dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

####不同的队列与函数的组合会有不同的效果* 并行队列+异步函数:创建新的线程,并行执行任务* 并行队列+同步函数:没有新的线程,串行执行任务* 串行队列+异步函数:创建新的线程,串行执行任务* 串行队列+同步函数:没有新的线程,串行执行任务* 主队列+异步函数:没有新的线程,串行执行任务* 主队列+同步函数:没有新的线程,串行执行任务(主队列虽然也是串行队列)####下面通过GCD实现单一资源线程安全的多读单写#####一 信号量#####简单来说就是控制访问资源的数量,比如系统有两个资源可以被利用,同时有三个线程要访问,只能允许两个线程访问,第三个应当等待资源被释放后再访问。#####二 使用#####* 创建信号量

dispatch_semaphore_t semaphore=dispatch_semaphore_create(1);// 1 是信号量的初始值 这里只允许一个线程访问

* 提高信号量

dispatch_semaphore_signal(semaphore)

* 等待降低信号量

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);// 如果semaphore计数大于等于1.计数-1,返回,程序继续运行。如果计数为0,则等待。

测试

dispatch_queue_t qune=dispatch_queue_create("x", DISPATCH_QUEUE_CONCURRENT);dispatch_semaphore_t semaphore=dispatch_semaphore_create(1);__block int i=1 , n=1;for (int index=0; index < 100; index++) {

    dispatch_async(qune, ^(){        i++;        NSLog(@"%d %d\n", index,i);            });    }/* 只能单写 */for (int index=0; index < 100; index++) {        dispatch_async(qune, ^(){                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//        n++;        NSLog(@"%d xx  %d\n", index,n);

// sleep(1);dispatch_semaphore_signal(semaphore);

    });    }打印LOG:2016-09-12 14:32:11.849 Mansory[4745:108806] 0 22016-09-12 14:32:11.849 Mansory[4745:108807] 2 42016-09-12 14:32:11.849 Mansory[4745:108805] 1 32016-09-12 14:32:11.850 Mansory[4745:108887] 3 52016-09-12 14:32:11.850 Mansory[4745:108888] 4 62016-09-12 14:32:11.851 Mansory[4745:108807] 6 82016-09-12 14:32:11.851 Mansory[4745:108806] 5 72016-09-12 14:32:11.851 Mansory[4745:108805] 7 92016-09-12 14:32:11.851 Mansory[4745:108887] 8 102016-09-12 14:32:11.851 Mansory[4745:108888] 9 11..index 是乱序的 因为是异步的   i值是乱序的 因为资源竞争的问题导致2016-09-12 14:32:11.863 Mansory[4745:108910] 0 xx  22016-09-12 14:32:11.863 Mansory[4745:108807] 99 1012016-09-12 14:32:11.868 Mansory[4745:108807] 39 xx  32016-09-12 14:32:11.868 Mansory[4745:108807] 42 xx  42016-09-12 14:32:11.868 Mansory[4745:108807] 43 xx  52016-09-12 14:32:11.868 Mansory[4745:108807] 45 xx  62016-09-12 14:32:11.868 Mansory[4745:108807] 46 xx  72016-09-12 14:32:11.868 Mansory[4745:108807] 48 xx  82016-09-12 14:32:11.869 Mansory[4745:108927] 50 xx  92016-09-12 14:32:11.869 Mansory[4745:108927] 51 xx  102016-09-12 14:32:11.869 Mansory[4745:108927] 53 xx  112016-09-12 14:32:11.869 Mansory[4745:108927] 54 xx  122016-09-12 14:32:11.869 Mansory[4745:108927] 56 xx  132016-09-12 14:32:11.869 Mansory[4745:108927] 57 xx  142016-09-12 14:32:11.870 Mansory[4745:108927] 59 xx  152016-09-12 14:32:11.870 Mansory[4745:108927] 61 xx  16..index 是乱序的 是异步的 n值是递增的有序的 资源安全
#### dispatch_group_t 队列同步* 手动管理group关联的block的运行状态

dispatch_group_t group=dispatch_group_create();__weak typeof(self) this=self;

dispatch_group_enter(group);[this productEvlute]; //网络请求self.requestProductSucess=^{//请求成功回调     dispatch_group_leave(group);};dispatch_group_enter(group);[this estimateServive]; //网络请求耗时操作  self.requestServiceSucess=^{ //请求成功      dispatch_group_leave(group);  };}..

dispatch_group_notify(group, dispatch_get_main_queue(), ^{//任务都完成回调[this checkIFAllCommitSucess];});/*进入dispatch_group_enter和退出dispatch_group_leave次数必须匹配*/

*   ````   dispatch_group_async(group, queue, ^{        //任务1   });     dispatch_group_async(group, queue, ^{        //任务2   });    .   .   dispatch_group_notify (group, queue, ^{        //任务都complete   });    ````

iOS多线程教程,看这里就够了

多线程----GCD

GCD好处用于多核的并行计算利用更多的内核在多核中自动管理线程的生命周期不需要编写任何线程管理代码GCD的任务和队列

任务 同步执行和异步执行 主要区别:是否等待队列的任务执行结束,是否具备开启新线程的能力队列 串行队列和并发队列 执行任务的等待队列,用来存放任务的队列,是一种特殊的线性表,采用先进先出的原则

多线程的六种组合方式同步 + 并发 不会开启新线程 同步 + 串行 不会开启新线程异步 + 并发 开启新线程异步 + 串行 不会开启新线程同步 + 主队列 在主线程中会锁死 其他线程中不会开启新线程异步 + 主队列 主线程中执行任务,不开启新线程GCD线程间的通讯

在主线程中进行UI的刷新操作,以及一些用户的点击操作等等,比较耗时的操作放在其他的线程,网络的请求,图片的下载等,完成之后回到主线程,实现线程之前的通讯/** * 线程间通信 */ - (void)communication { // 获取全局并发队列 dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 获取主队列 dispatch_queue_t mainQueue=dispatch_get_main_queue(); dispatch_async(queue, ^{ // 异步追加任务 1 [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程 // 回到主线程 dispatch_async(mainQueue, ^{ // 追加在主线程中执行的任务 [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程 }); }); }

GCD栅栏方法:dispatch_barrier_async

应用例子:就是我们需要异步执行两组数据 需要在A执行完了之后再去执行B的操作,就需要使用GCD栅栏方式

GCD延时操作:dispathc_after

应用例子:在指定时间结束之后执行某个任务,就可以使用这个方式

GCD单利创建:dispatch_once

应用例子:创建单利的使用

GCD快速迭代方法:dispatch_apply

dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply(7, queue, ^(size_t index) { NSLog(@"这里是我返回的数据:%zu",index); });

GCD队列组 dispatch_group

应用例子:异步执行多个操作之后,需要等操作结果都出来之后再去主线程刷新UI的操作

GCD信号量 dispatch_semaphore 信号量 计数器小于0,不可以通过,为0或者大于0就可以通过dispatch semaphore 线程安全和线程同步 为线程加锁

使用场景:购物车购买流程 非线程安全的话就会出现排序不一致的情况,就是购物车剩余产品返回有问题 线程安全就不会出现这个问题/** * 线程安全:使用 semaphore 加锁 * 初始化火车票数量、卖票窗口(线程安全)、并开始卖票 */ - (void)initTicketStatusSave { NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程 NSLog(@"semaphore---begin"); semaphoreLock=dispatch_semaphore_create(1); self.ticketSurplusCount=50; // queue1 代表北京火车票售卖窗口 dispatch_queue_t queue1=dispatch_queue_create("net.bujige.testQueue1", DISPATCH_QUEUE_SERIAL); // queue2 代表上海火车票售卖窗口 dispatch_queue_t queue2=dispatch_queue_create("net.bujige.testQueue2", DISPATCH_QUEUE_SERIAL); __weak typeof(self) weakSelf=self; dispatch_async(queue1, ^{ [weakSelf saleTicketSafe]; }); dispatch_async(queue2, ^{ [weakSelf saleTicketSafe]; }); } /** * 售卖火车票(线程安全) */ - (void)saleTicketSafe { while (1) { // 相当于加锁 dispatch_semaphore_wait(semaphoreLock, DISPATCH_TIME_FOREVER); if (self.ticketSurplusCount > 0) { // 如果还有票,继续售卖 self.ticketSurplusCount--; NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@", self.ticketSurplusCount, [NSThread currentThread]]); [NSThread sleepForTimeInterval:0.2]; } else { // 如果已卖完,关闭售票窗口 NSLog(@"所有火车票均已售完"); // 相当于解锁 dispatch_semaphore_signal(semaphoreLock); break; } // 相当于解锁 dispatch_semaphore_signal(semaphoreLock); } }dispatch_semaphore_create //创建并初始化信号量总量 dispatch_semaphore_signal //信号量加1 dispatch_semaphore_wait //信号量减1

发表评论