iOS 多线程: dispatch_barrier_async

iOS 多线程-GCD栅栏方法 上一篇文章记录了队列组的使用,是为了处理多个任务之间的顺序。但是开发中会出现多组任务的顺序问题。 例如:现在有两组任务,每组任务中有多个任务需要并发处理,但是两组任务之间需要顺序执行。这个时候需要用到GCD多线程处理的另一种方式:栅栏方法(dispatch_barrier_async)。 栅栏方法(dispatch_barrier_async) 栅栏方法:就是像筑起一个栅栏一样,将队列中的多组线程... 阅读详情

该篇是 「iOS 多线程」系列的第三篇.

前面两篇可以戳击下面的链接.

iOS 多线程: 正确认识 GCD 队列类型
iOS 多线程: 信号量

该系列博客是为了记录和分享自己关于 iOS 多线程的一些认识, 结合工作中遇到的问题, 和大家交流.

欢迎拍砖.

在这里你可以完整的查看 dispatch_barrier 的文档.

关于dispatch_barrier_async, 有这样的描述:

Discussion
Calls to this function always return immediately after the block has been submitted and never wait for the block to be invoked. When the barrier block reaches the front of a private concurrent queue, it is not executed immediately. Instead, the queue waits until its currently executing blocks finish executing. At that point, the barrier block executes by itself. Any blocks submitted after the barrier block are not executed until the barrier block completes.

The queue you specify should be a concurrent queue that you create yourself using the dispatch_queue_create function. If the queue you pass to this function is a serial queue or one of the global concurrent queues, this function behaves like the dispatch_async function.

中文翻译大概如下:

一个dispatch barrier 允许在一个并发队列中创建一个同步点。当在并发队列中遇到一个barrier, 他会延迟执行barrier的block,等待所有在barrier之前提交的blocks执行结束。 这时,barrier block自己开始执行。 之后, 队列继续正常的执行操作。

调用这个函数总是在barrier block被提交之后立即返回,不会等到block被执行。当barrier block到并发队列的最前端,他不会立即执行。相反,队列会等到所有当前正在执行的blocks结束执行。到这时,barrier才开始自己执行。所有在barrier block之后提交的blocks会等到barrier block结束之后才执行。

这里指定的并发队列应该是自己通过dispatch_queue_create函数创建的。如果你传的是一个串行队列或者全局并发队列,这个函数等同于dispatch_async函数。

Get point:

通过dispatch_barrier_async函数提交的任务会等它前面的任务执行完才开始,然后它后面的任务必须等它执行完毕才能开始.
必须使用dispatch_queue_create创建的队列才会达到上面的效果.

看一个例子

 // 自定义并发队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);

dispatch_sync(concurrentQueue, ^() {
    NSLog(@"dispatch_sync--1");
});

dispatch_sync(concurrentQueue, ^() {
    NSLog(@"dispatch_sync--2");
});

dispatch_barrier_async(concurrentQueue, ^() {
    NSLog(@"dispatch-barrier_async");
    sleep(1);
});

// 同步, (可以改为异步, 3-4顺序就不一致了)
dispatch_sync(concurrentQueue, ^() {
    NSLog(@"dispatch_sync--3");
    sleep(1);
});

dispatch_sync(concurrentQueue, ^() {
    NSLog(@"dispatch_sync--4");
});

不管你执行多少次, 结果都是一样的.

dispatch_sync--1
dispatch_sync--2
dispatch-barrier_async
dispatch_sync--3
dispatch_sync--4

可以看出dispatch-barrier_async阻塞了后面的操作.

上面的执行时在并发队列中,如果在串行队列中呢?

// 自定义串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_SERIAL);

dispatch_async(serialQueue, ^() {
    NSLog(@"dispatch_async--1");
});

dispatch_async(serialQueue, ^() {
    NSLog(@"dispatch_async--2");
});

dispatch_barrier_async(serialQueue, ^() {
    NSLog(@"dispatch-barrier_async");
    sleep(1);
});

// 虽然异步, 但是在串行队列中, 会按照顺序执行
dispatch_async(serialQueue, ^() {
NSLog(@"dispatch_async--3");
    sleep(1);
});

dispatch_async(serialQueue, ^() {
    NSLog(@"dispatch_async--4");
});

执行结果和上面一样.

我们可以利用 dispatch_barrier 的特性实现读写安全的模型.

这里使用缓存来说明.

Cache.h

#import <Foundation/Foundation.h>

@interface Cache : NSObject

+ (instancetype)sharedCache;

- (id)cacheWithKey:(id)key;

- (void)setCacheObject:(id)obj withKey:(id)key;

@end

Cache.m

#import "Cache.h"

static Cache *_instance;

@interface Cache ()

@property (nonatomic, strong) NSMutableDictionary *cache;

@end

@implementation Cache
{
    dispatch_queue_t queue;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });

    return _instance;
}

+ (instancetype)sharedCache
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] _init];
    });

    return _instance;
}

- (instancetype)_init
{
    if (self = [super init]) {
        queue = dispatch_queue_create("cache_gcd_mark", DISPATCH_QUEUE_CONCURRENT);
        _cache = [NSMutableDictionary dictionaryWithCapacity:10];
    }

    return self;
}

- (id)cacheWithKey:(id)key
{
    __block id obj;

    // 任意线程都可以'读'
    dispatch_sync(queue, ^{
        obj = [self.cache objectForKey:key];
    });

    return obj;
}

- (void)setCacheObject:(id)obj withKey:(id)key
{
    // 保证同时'写'的的只有一个
    dispatch_barrier_async(queue, ^{
        [self.cache setObject:obj forKey:key];
    });
}

@end

关于 dispatch_barrier_sync, 大家可以先自行探索.
后面有关于这方面的问题, 再分享给大家.

顺便讨论一下 dispatch_barrier_async_f 函数.

函数原型:

void dispatch_barrier_async_f(dispatch_queue_t queue,
    void *context,
    dispatch_function_t work);

参数:
1. queue : 队列.和 dispatch_barrier_async 一样, 需要自己创建的队列, 才有阻塞的作用.
2. context: void * 类型.可以作为 work 的参数.
3. work : 函数指针.
该函数指针定义如下:

typedef void (*dispatch_function_t)(void *)

举个例子(ARC):

dispatch_queue_t queue = dispatch_queue_create("mark.gcd.barrier", DISPATCH_QUEUE_CONCURRENT);

// 有参数函数        
NSString *msg = @"print info.";
dispatch_function_t func = printInfo;
// 需要使用 bridge 进行转换
dispatch_barrier_async_f(queue, (__bridge void *)(msg), func);

// 无参数       
dispatch_function_t noParamFun = myfunc;
dispatch_async_f(queue, 0, noParamFun);

输出结果如下:

msg: print info.
no param.
GCD学习之dispatch_barrier_async dispatch_barrier_async 在访问数据库或文件时,使用Serial Dispatch Queue可避免数据竞争的问题。 写入处理确实不可与其他的写入处理以及包含读取处理的其他某些问题并行执行。但是如果读取处理只是与读取处理并行执行,那么多个并行执行就不会发生问题。 为了高效率地进行访问,读取处理追加到Concurrent Dispatch Queue中,写入处理在 阅读详情

相关推荐

一文读懂无人机AI识别算法,原理、技术、应用

本文详细介绍了无人机识别算法的工作原理、技术优势以及在多个行业的应用前景,展现了其在提升安全监控、资源管理和应急响应中的关键作用。尽管无人机识别算法在多个领域展现出巨大潜力,但仍面临技术挑战,如算法的准确性、数据的实时处理能力以及对复杂环境的适应性。4. 消防与城市管理: 无人机识别算法在消防和城市管理中的应用,为相关部门提供了及时的信息支持,提升了应急处置能力和城市管理水平。1. 公安监控: 无人机识别算法在公安领域的应用,可以实时识别犯罪嫌疑人和违法行为,有效提升城市治安管理的智能化水平。

foiadrone的博客 1849

iOS多线程---GCD中的栅栏函数

一、什么是栅栏函数 dispatch_barrier_async函数,在进程管理中起到一个栅栏的作用,它等待所有位于barrier函数之前的操作执行完毕后执行,并且在barrier函数执行之后,barrier函数之后的操作才会得到执行,该函数需要同dispatch_queue_create函数生成的DISPATCH_QUEUE_CONCURRENT队列一起使用。

旭日的博客 1680

AI Agent的知识蒸馏链:多阶段LLM模型优化

随着大语言模型(LLM)规模的不断扩大,如何在保持模型性能的同时提高其部署效率成为关键挑战。本文旨在探讨通过知识蒸馏技术构建多阶段优化链,实现LLM模型的高效压缩和性能优化。研究范围涵盖从基础理论到实际应用的完整知识蒸馏流程,特别关注AI Agent场景下的特殊需求和解决方案。本文首先介绍知识蒸馏的基本概念和背景,然后详细阐述多阶段蒸馏链的核心原理。接着,我们将深入探讨算法实现细节和数学模型,提供完整的代码示例。最后讨论实际应用、工具资源和未来发展方向。

AI大模型应用之禅 353

【iOS】GCD深入学习

本篇主要介绍GCD中的方法。

m0_63852285的博客 1325

手把手教你学Simulink--复杂环境适应的四足机器人领域仿真建模实例:构建一个基于Simulink的四足机器人动态平衡保持仿真模型

通过上述步骤,你可以构建一个基本的基于Simulink的四足机器人动态平衡保持仿真模型。此模型不仅有助于理解四足机器人在复杂环境中的动态平衡控制原理,也为进一步优化提供了基础。随着技术的发展,还可以探索更多高级功能,如自适应步态调整、强化学习等,以提高机器人的智能性和适应性。

MHD0815的博客 240

QT自制TCP服务器

TCP服务器 网络调试助手

大脑曝光 3628

并发编程 - GCD的栅栏(dispatch_barrier_async)

在本文中,我们深入探讨了GCD栅栏操作的高级用法,通过实际示例展示了如何在并发队列中执行任务的顺序控制和实现读写锁。栅栏操作是处理复杂并发任务时非常强大的工具,它能够确保任务的顺序执行,避免数据不一致或冲突。然而,在使用栅栏操作时,需要特别注意一些关键点。首先,尽量避免在全局并发队列中使用栅栏操作,因为全局并发队列通常用于系统级任务。栅栏操作的使用应局限于专门为特定任务创建的并发队列,这样可以更好地控制执行任务的顺序。

weixin_39339407的博客 1301

【Bug已解决】Auto mode cannot determine the safety of an action — Claude Code 自动模式安全判断失败解决方案

将已知安全的操作添加到白名单,分类器不再拦截这些操作。# 步骤 1:编辑 Claude Code 配置"Read","Write"EOF# 步骤 2:白名单中的操作将自动通过# 不在白名单中的操作仍需分类器判断# 步骤 3:重启 Claude Codeclaude方案适用场景推荐指数难度方案一:手动审批偶发回退,安全优先⭐⭐⭐⭐⭐低方案二:/compact 压缩上下文超限导致⭐⭐⭐⭐低方案三:拆分步骤复杂操作触发⭐⭐⭐⭐低方案四:跳过审批隔离环境,CI/CD。

博客 1万+

GCD全解-dispatch_barrier_sync/async-栅栏函数

文章目录1、前言2、同步栅栏函数:dispatch_barrier_sync2、异步栅栏函数:dispatch_barrier_async4、总结分析5、栅栏函数 与 自定义并发队列 1、前言 需求:假设有4个任务{1,2,3,4},执行完前2个再执行后2个 这里我们用到栅栏函数dispatch_barrier_(a)sync,(也可以用队列组),我们要注意的是不能使用全局并发队列(系统提供给我们的)否则会散失栅栏函数的意义。 # 栅栏函数仅与并发队列(DISPATCH_QUEUE_CONCURRENT)中

chenzimin_blog 1515

ESP32设备驱动-AS5600磁性旋转位置传感器

AS5600 是一款可编程的 12 位高分辨率非接触式磁性旋转位置传感器。 AS5600可以作为磁性电位器或磁性编码器使用,具有出色的可靠性和耐用性。 与传统电位器/编码器相比,AS5600具有显着优势:高精度、非接触式、旋转角度无限制。 所有这些优点使其适用于非接触式角度测量应用,例如机器人手臂、云台、电机闭环控制、机床轴定位。

视觉与物联智能 2553

【系统分析师】2025年下半年真题:案例分析-答案及详解(回忆版)

Redis相比Memcached在电商高并发场景下具有显著优势:支持持久化(RDB/AOF)、丰富数据结构(如有序集合实现排行榜)、原生支持集群和哨兵模式(高可用性)。布隆过滤器通过位数组和哈希函数预先存储所有合法订单ID,当查询请求到达时快速拦截无效ID(如伪造ID),避免其穿透缓存直接冲击数据库,从而预防缓存击穿问题。

数据知道的博客 5998

IOS多线程的一些总结

一直觉得多线程是一块难啃的骨头,倒不是因为他有多难,只是因为心里想这很难,在平时的学习和工作中总会有意无意的避开多线程的使用。今天写这篇文章倒不是因为掌握的多好,只是对多线程的随笔,下次看到也不至于太陌生。主要对IOS中GCD以及NSOperationQueue的一些梳理

不积跬步,无以至千里;不积小流,无以成江海。 1104

RK3588部署YOLOv11与RKNN全流程教程

本文详细介绍了在RK3588开发板上部署YOLOv11目标检测模型的全流程。主要内容包括:PC端CUDA/cuDNN环境配置、Anaconda虚拟环境搭建、RKNN Toolkit2安装;YOLOv11模型从PyTorch到ONNX再到RKNN的格式转换;以及RK3588开发板的系统配置、RKNPU驱动安装和最终推理实现。教程提供了完整的代码示例,帮助开发者快速在边缘设备上实现高效的AI推理应用,涵盖从环境准备到实时检测的全套解决方案。

FJN110的博客 379

iOS多线程编程系类

目录: IOS多线程编程之NSThread的使用 IOS多线程编程之NSOperation和NSOperationQueue的使用 IOS多线程编程之Grand Central Dispatch(GCD)介绍和使用 IOS多线程编程之NSThread的使用 1、简介: 1.1 IOS有三种多线程编程的技术,分别是: 1.、NSThread 2、Coc

1171

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

iOS - 多线程-读写安全

操作,那是非常危险的事情,会造成数据错乱。操作其实不会影响原数据,因此是可以允许。可以解决问题,但是针对该场景,将其与其它线程隔离开。

sharp521的博客 1175

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

GCD全解-04-dispatch_barrier_sync/async-线程阻塞

dispatch_barrier_sync dispatch_barrier_async demo 小结 dispatch_barrier_sync # Submits a barrier block for synchronous execution on a dispatch queue. # relevant only on DISPATCH_QUEUE_CONCUR...

zhuge1127的博客 1682

iOS 多线程面试题(dispatch_barrier_async)

dispatch_barrier_async 1、问:怎么用GCD实现多读单写? 多读单写的意思就是:可以多个读者同时读取数据,而在读的时候,不能取写入数据。并且,在写的过程中,不能有其他写者去写。即读者之间是并发的,写者与读者或其他写者是互斥的。 这里的写处理就是通过栅栏的形式去写。 就可以用dispatch_barrier_sync(栅栏函数)去实现 2、dispatch_barrie...

小丑鱼 670

iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

介绍:Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统。这建立在任务并行执行的线程池模式的基础上的。它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用。设计:GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。一个任务可以是一个函数(f

空杯子 15万+

栅栏函数dispatch_barrier_sync/async

有几个并行执行的操作:1,2,3,4,5 如果我们想要在1,2,3执行完毕后,执行A操作,然后再执行4,5 那么我们就可以使用栅栏函数来解决; 1、使用dispatch_barrier_sync 串行 函数: 在插入队列的时候是串行的,在任务真正执行的过程中也是串行的。 - (void)testCustomBarrier{ dispatch_queue_t currentQueue = d...

whxuan_ios的博客 611

iOS多线程中performSelector: 和dispatch_time的不同

我们知道:只有主线程会在创建的时候默认自动运行一个runloop,并且有timer,普通的子线程是没有这些的。这样就带来一个问题了,有些时候我们并不确定我们的模块是不是会异步调用到,而我们在写这样的延时调用的时候一般都不会去检查运行时的环境,这样在子线程中被调用的时候,我们的代码中的延时调用的代码就会一直等待timer的调度,但是实际上在子线程中又没有这样的timer,这样我们的代码就永远不会被调到。

郭晓东的专栏 1万+

dispatch_barrier_栅栏函数 iOS之多线程GCD(三)

dispatch_barrier_async场景需求:需要异步完成三个任务。任务一、任务二、任务三。要求:任务三必须在任务一、任务二完成之后触发。这就需要使用dispatch_barrier_async。特点:像一堵围墙、成为任务的分割线。代码如下:dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CO...

weixin_34635170的博客 320

dispatch_barrier_async一些用法

- (NSDictionary *)HTTPRequestHeaders { NSDictionary __block *value; dispatch_sync(self.requestHeaderModificationQueue, ^{ value = [NSDictionary dictionaryWithDictionary:self.mutableHTT

chenmo230的博客 743

iOS面试:dispatch_barrier_async的作用是什么?

是 Grand Central Dispatch (GCD) 中的重要函数,主要用于并发队列中,以确保在某些特定情况下的线程安全和操作顺序。是一个强大的工具,用于管理并发队列中的读写操作,防止数据竞争,并保证操作的顺序。当没有写权限的操作并行执行时,性能会更高。例如,先进行多个数据读取操作,然后再执行一次数据写入操作,这样可以保证写操作是最后被执行的。在并发队列中,当有读(读取数据)和写(修改数据)的操作时,可能会导致数据的不一致性。在写操作完成后,后续的读取任务可以继续执行,这确保了数据的完整性。

androiios的博客 542

iOS开发系列-线程同步dispatch_barrier_(a)sync

参考 //参数1:将barrier添加到的队列 //参数2:barrier执行的block void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block); void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);...

硅谷热的博客 693

[转] iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统。这建立在任务并行执行的线程池模式的基础上的。它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用。 设计: GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。 一个任务可...

weixin_34310369的博客 214

iOS多线程开发——GCD的使用与多线程开发浅析(二)

对于iOS多线程开发,我们时刻处于学习之中,在看书中,看文档中,项目开发中,都可以去提高自己。最近刚看完了《Objective-C高级编程 iOS与OS X多线程和内存管理》这本书后,对多线程有了更为深入的理解,故在此做一个总结与记录。这本书我已经上传至网盘  https://pan.baidu.com/s/1c2fX3EC ,这本书是iOS开发者必读的书之一,写得很不错,欢迎大家下载阅读。书的封

乞力马扎罗的雪CYF的博客 1万+
上一篇: iOS 多线程: 信号量
下一篇: iOS 音视频: 编译 FFmpeg-3.1.1
veryitman
博客等级 码龄16年 472粉丝 310原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值