自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(117)
  • 收藏
  • 关注

原创 trace-cmd记录线程被中断打断的时间

(3)执行任务过程中有内存操作,内存操作肯呢个引起缺页中断,用户同样的内存操作,有缺页中断和无缺页中断,所消耗的时间是不一样的。使用trace-cmd report可以查看监听结果,结果如下,通过结果进一步分析,我们就可以确定线程被中断打断的时间。(5)以上情况都没有,但是同样优先级的线程比较多,也就是系统负载比较高,这个线程的运行需要排队等待。(1)线程主动让出了cpu,比如线程中出现了sleep,使用了互斥体,等待io等。(2)线程被动让出cpu,线程被更高优先级的线程抢占。

2025-08-03 21:03:50 285

原创 xdp 入门

xdp 全称 eXpress Data Path,是 linux ebpf 中的一个功能。ebpf 在内核中预留了一些插入点,用户可以在这些插入点插入自己的处理逻辑,当数据路过插入点时可以做一些预期的处理,具体实现方式如下:① 用户编写数据处理代码,也就是对于路过这个插入点的数据想做什么处理② 将代码编译③ 将编译好的目标文件安装到插入点安装之后,数据路过插入点时便会被安装的代码处理。插入点的处理逻辑就像一些路口的收费站,不同身份的车辆通过收费站的时候,可能需要做不同的事情。

2024-02-28 18:08:19 4927

原创 linux下怎么定位内存泄漏

正常情况下,软件使用的内存是随着时间在一定范围内波动的。内存泄漏说的是随着时间的推移,进程使用的内存越来越多。一般情况下,内存泄漏是程序不断地申请内存,但是没有释放导致的。

2024-02-27 14:55:33 3688

原创 使用cgroup踩过的坑

cgroup 全称 control group,控制组。通过 cgroup 可以限制应用使用的资源,资源包括 cpu、内存、磁盘 io、网络等。工作中经常使用的 docker 容器就使用了 cgroup 进行资源限制和隔离,cgroup 是 docker 的基础。

2024-02-18 22:08:43 6432

原创 SCHED_FIFO 和 SCHED_RR 同时存在时,如何调度

(1)从上边的实验现象可以看出来,实验现象符合 SCHED_FIFO 先入先出,SCHED_RR 时间轮询的调度原理。(2)在实时调度策略中,高优先级具有绝对的优先调度的的特权,即使 SCHED_RR 这种时间片轮询的调度算法,也是说的多个 SCHED_RR 的优先级相等的前提下才会轮询,如果优先级不相等,那么只会调度优先级最高的那个线程。

2024-01-19 21:03:55 3133 1

原创 linux 中进程的 D 状态和 Z 状态

僵尸态是 linux 进程的一种状态,用 Z (zombie) 表示。处于 Z 状态的进程已经不在工作,进程的资源(内存,打开的文件) 都已经释放,只保留 struct task_struct 一个空壳子,用僵尸来表示这个状态非常形象。僵尸进程不能被信号杀死(因为僵尸进程已经死了,当然也不能响应信号),只能被父进程回收。进程处于僵尸态时保存的信息非常少,其中包括进程号,退出码,退出码是比较重要的,父进程回收僵尸进程的时候可以根据退出码确定子进程的退出原因。

2024-01-13 11:05:54 5994 1

原创 linux中fd的几点理解——一切皆文件

fd 全称是 file descriptor,文件描述符,又称句柄。当我们在打开一个文件,创建一个 socket, 创建一个 epoll 时,返回值往往都用一个变量 int fd 来表示。

2024-01-13 10:35:03 4532 1

原创 fastdds qos:OwnershipQosPolicy、OwnershipStrengthQosPolicy

DataWriter1和DataWriter2的OwnershipQosPolicy都是独占类型,OwnershipStrengthQosPolicy的strength分别是100和90。TODO:待验证,通过tcpdump抓包,在DataReader所在的机器,能抓到DataWriter2发送的数据。当DataWriter1和DataWriter2同时存在时,DataWriter2的数据会真正被发送,也会被DataReader所在的进程接收,但是对于用户是读取不到DataWriter2的数据的。

2025-08-29 07:18:27 68

原创 fastdds:topic instance

如果让我们自己实现,我们在定义数据类型的时候,除了摄像头数据之外,我们还可以增加一个id属性,用id来区分数据来源于哪个摄像头,这种方式直观,好理解,完全可行。从fastdds example中的topic instances例子来看,DataWriter在创建的时候,可以针对每个key创建一个句柄,这样在发送数据的时候,不需要对数据类型中的key字段进行赋值,只需要使用key对应的句柄进行发送即可。试想,如果我们自己实现对每个instance的状态机的维护,还是有一定的复杂度的。

2025-08-24 22:01:35 339

原创 fastdds qos:DurabilityQosPolicy

假如DataWriter先起来,并且已经写了一些数据,之后有新的DataReader起来,那么新起来的DataReader能不能接收到它启动之前,DataWriter发布的数据呢。DurabilityQosPolicy用来做这种控制。VOLATILE_DURABILITY_QOS:易失的,新上线的DataReader只能读取上线之后,DataWriter发布的数据。

2025-08-23 17:40:30 684

原创 fastdds qos:DeadlineQosPolicy

DeadlineQosPolicy这种qos使用在DataWriter、DataReader、Topic。该qos用来监督数据是不是按照预期的频率进行收发。假如数据是周期性发送和接收,周期是固定的100ms,我们如果想要监督数据收发是不是按照预期的周期进行的,那么就可以配置DeadlineQosPolicy。以fastdds example中的hello_world为例,数据每100ms发送一次,我们配置DataWriter和DataReader的deadline为90ms,

2025-08-23 14:40:14 438

原创 linux线程被中断打断,不会计入调度次数

通过线程的status文件,可以查看线程的调度次数。status的最后两行,voluntary_ctxt_switches表示线程的资源调度次数,比如线程调用了sleep睡眠,或者调用io接口发生了阻塞,均会统计为主动调度次数;nonvoluntary_ctxt_switches表示非自愿调度次数,比如线程在运行过程中被强张了。

2025-08-17 21:17:35 223

原创 tcp会无限次重传吗

超过这个次数,tcp会放弃重传,然后通过函数tcp_write_err将套接字的状态置错误。socket状态置为错误之后,针对这个socket的阻塞调用,比如read,epoll_wait等便会返回,但是返回值表示错误。tcp作为面向连接的,可靠的,字节流。最终要的特点就是可靠,其中重传又是保证可靠的重要前提。那么当tcp发送数据之后,收不到ack的情况下,会无限次重传吗。超过这个次数,tcp会将信息报告给网络层,网络层会进行一些操作,比如缓存的更新等。在建立连接的阶段,syn报文的重传次数。

2025-08-17 20:50:47 250

原创 linux下timerfd和posix timer为什么存在较大的抖动?

在linux中开发引用,timerfd和posix timer是最常用的定时器。timerfd是linux特有的定时器,通过fd来实现定时器,体现了linux"一切皆文件"的思想;posix timer,只要符合posix标准的操作系统,均应支持。在开发确定性应用时,需要选用确定性的定时器。搜索网络上的一些资料,往往说这两种定时器的精度可以达到纳秒级。但是在实际测试中,尤其是在压测时,即使linux打了实时补丁,两种定时器的抖动也会比较大,可以达到700μs,甚至更大。

2025-08-17 19:02:12 1002

原创 fastdds:默认qos

Publisher、Subscriber、DataWriter、DataReader、Topic均可以应用qos策略,不同的qos策略的使用范围是不一样的:DeadelineQosPolicy适用于Topic、DataWriter、DataReader;具体每种策略的适用范围,可以看官方文档的描述,也可以看fastdds源码,以TopicQos为例,源码中唵TopicQos类来管理,其中的汽油成员如下,说明这些qos策略适用于qos。(3)qos策略需要匹配,通信的双方才能通信。(2)qos策略适用对象。

2025-07-23 21:58:42 371

原创 c++无锁队列moodycamel::ConcurrentQueue测试结果

在c++开发中,无锁队列moodycamel::ConcurrentQueue使用较多,示意图如下:从宏观来看moodycamel::ConcurrentQueue是MPMC队列,即多生产者,多消费者队列;从微观来看,是SPMC队列,即单生产者,多消费者队列。在ConcurrentQueue中,没个生产者都有自己对应的队列。这也引入了ConcurrentQueue的一个特点:ConcurrentQueue只能保证单个生产者的FIFO特性,即对于一个生产者来说,元素出队的顺序和入队的顺序是一样的。

2025-07-13 13:40:23 817

原创 优先级继承和优先级天花板(pthread_mutexattr_setprotocol)

在B获取锁之后,释放锁之前,A想要获取锁,这个时候,如果B线程没有被其它线程抢占,正在运行,那么A等待B执行完毕即可,符合预期,既然用户实现了这样的业务,即两个不同优先级的线程会抢一个锁,那么就要有这样的预期。而如果这个时候出现了第三个线程C,C的优先级大于B,小于A,那么这个时候C会抢占B的执行,这种现象导致的结果才是不符合预期的。在B获取锁之后,释放锁之前,A想要获取锁,这个时候为了让B尽快执行完,会将A的优先级提升到B的优先级。那么不管哪个线程获取到锁,或者在等待锁,那么线程的优先级都是调整为30。

2025-06-21 16:11:26 324

原创 leetcode:最小覆盖字符串

对于算法题目,自己能想到的往往是最基础的笨方法。代码如下:如果t的长度是len1,s的长度是len2,那么最小窗口是len1,最大窗口是len2。所以可以从len1到len2,遍历窗口大小,对于每个窗口大小,将窗口从前向后进行移动。因为窗口是从小到大进行遍历,所以第一次遇到满足条件的子串时,就可以直接范围。这种算法的时间复杂度是O(n*n),在leetcode上运行会超时。

2025-05-04 18:44:30 432

原创 递归下降算法

在软件开发中有这样一个需求,开发语言是c++,用户可以通过配置指定任务依赖的事件,比如配置e1|e2|e3的意思是,e1、e2、e3 3个事件,只要有一个到来,那么条件就是满足的,任务可以执行;在比如,用户还可以配置(2*e1 | e2) & e3,这样复杂的逻辑,表示e3是必要的,另外e1到来两次或者e2到来一次也是必要的。事件的个数不仅仅是3个,还可以更多,逻辑关系包含|表示或,&表示与,*表示时间到来的次数,逻辑关系可以任意组合。之前只听说和使用过递归算法,递归算法就是在函数内部调用函数本身。

2025-05-04 18:15:41 352

原创 uml类关系(实现、继承,聚合、组合,依赖、关联)

drawio和EA是架构设计时经常使用的画图工具。drawio学习门槛低,使用灵活,但是功能仅仅限于画图。EA学习门槛高,但是功能更加的丰富:①在画图方面,EA严格满足UML标准,EA中的图和类是关联的,如果修改了一个类的名字或者函数等,在引用这个类的图中也会自动修改②EA还可以将架构设计时定义的类、接口等导出为代码③EA可以导入已有的代码,生成类图。

2025-04-26 17:40:21 1193

原创 fastdds:传输层SHM和DATA-SHARING的区别

下图是fastdds官方的图,清晰地展示了dds支持的传输层:根据通信双方的相对位置(跨机器、同机器跨进程、同进程)的不同选择合适的传输层,是通信中间件必须要考虑的事情。跨机器通信,只能通过网络, fastdds支持UDP和TCP。在同一个机器中,使用UDP和TCP进行通信,当然也是可以的。但是,从性能的角度来考虑,更推荐使用SHM,SHM和UDP/TCP相比有2点优势:1、减少系统调用次数共享内存创建完成之后,后边使用的时候直接是内存操作,而UCP/TCP每次发送或者接收的的时候,都要通过系统调用。

2025-04-18 21:37:23 1333

原创 fastdds:传输层端口号计算规则

假如A发布的多播消息,那么B和C都会收到,如果B和A之间有相同topic的writer和reader,也就是说B和A是可以通信的,那么B就会向A发送单播消息,进行后续的协商,后边的协商过程均通过单播来实现。participantId的分配如下代码所示,同一个进程的同一个domain内,participantId都是从0开始的,也就是说participantId并不是domain内唯一的,而是domain和进程内唯一的。同样的,如果单播端口已经被占用,那么就会进行重试,重试的算法是在上一个端口的基础上加2。

2025-03-30 20:25:07 1149

原创 stack smashing detected

本文先介绍stack smashing detected问题现象,然后介绍问题产生的原因,最后介绍问题定位思路。

2025-03-22 12:05:24 1126

原创 leetcode:单词距离

遍历数组,当遍历到word1时更新index1,遍历到word2时更新index2。当index1和index2均不为-1时,则计算两者之差,如果两者之差比上一次计算的值小,则进行更新,否则不更新。对于这种情况,上边的两种方式,都可以解决,缺点是时间复杂度偏高。想要避免这种重复的工作,可以在第一次遍历的时候将每个单词的下标用map保存下来,map的key是word,value是单词下标的vector,单词下标从小到大进行存放。题干中说,如果文件多次输入,并且每次的两个单词都不相同,能不能优化?

2025-03-08 10:10:41 322

原创 设计模式:迭代器模式

但是对于一些复杂的数据结构,比如二叉树、map、set等,遍历操作就比较复杂,如果每次遍历这样的数据结构都要自己写遍历代码,这样的工作效率是比较低下的。这就给我们提供了一些写代码的思路,即使没有学习过设计模式,那么在写代码的时候,也可以想代码实现的是不是一个独立的、高内聚的功能,这样的代码是不是可以抽象出来,提高复用性。对于线性数据结构来说,迭代器模式,和直接使用下边的方式,复杂成都市差不多的,但是对于复杂的数据类型,比如map或者set,迭代器就有用了。比如编程语言标准库中的代码,修改的频率是比较低的。

2025-03-05 21:35:01 487

原创 std::thread:join/detach

用于线程间同步,特别是在主线程退出的时候,等待进程中的所有其它线程都退出之后,主线程再退出,这样能保证进程安全的退出。试想,如果主线程退出的时候,有其它线程还在运行,很容易导致进程的退出码不是0,或者被信号杀死。因为进程退出的时候就要释放所有的资源,而此时还在运行的线程可能会使用已经释放的资源,这样就会导致段错误。调用join之前,需要使用joinable进行判断现成是不是可join,如果线程不可join,那么调用join会抛异常。

2025-03-02 15:18:05 634

原创 设计模式:代理模式

代理模式是很常见的设计模式,即使没有专门学习过这种设计模式,在工作中也一定用过这种设计模式。在实际生活中,代理模式也是常见的,比如内阁首辅相对于皇帝,前者是后者的代理,内阁首辅收到奏折时,往往也要做一些预处理和后处理。当我们需要给原始类增加一些功能、日志、性能监控时,通过修改原始类当然是可以实现的,但是这样就侵入了原来的逻辑,违背了开闭原则。并且新增的功能与原有的功能本来就属于不同范畴的功能。在不修改原始类的基础上,增加新的功能,就需要用到代理模式。有些类也是无法修改的,这种情况下,只能使用代理模式。

2025-02-16 17:58:07 494

原创 设计模式:状态模式

状态机有3个要素:状态,事件,动作。假如一个对象有3个状态:S1、S2、S3。影响状态的事件有3个:E1、E2、E3。每个状态下收到对应事件的时候,对象的动作为AXY。那么该对象的状态机就可以用如下表格来表示。S1收到事件E1的时候动作为A11,收到事件E2的时候动作为A12,收到事件E3的时候动作为A13,以此类推。其中,动作可以是状态发生切换,也可以是其它与业务有关的动作。

2025-02-16 12:10:36 1214

原创 linux内核网络分层概述

在开发应用时,我们使用 socket 实现网络数据的收发。以tcp为例,server端通过 socket, bind, listen来创建服务端,然后通过 accept接收客户端连接;客户端通过 socket和 connect系统调用来创建客户端。用于数据收发的系统调用包括 send, recv, sendto, recvfrom等。除了上述系统调用之外,另外还有多路复用技术 select,poll, epoll,也常常在网络应用中使用。在做应用开发时,使用上述系统调用比较简单和简洁。对于 linux

2024-12-22 09:43:32 951

原创 fastdds:idl

在学习idl之前,先来回顾一下我们在开发中,通过网络收发数据时,常常怎么实现。上边是一个c语言中经常使用的通过网络收发数据的例子,包括两个步骤:(1)定义一个结构体来表示用户的数据(2)收发的时候直接使用结构体的地址和大小这种方式,有以下三点需要注意:(1)适用于字节序相同的机器,如果发送端和接收端所在的机器字节序不同,那么可能会有问题。(2)适用于相同语言之间的收发,不能跨语言。(3)直接发送结构体大小的数据,没有进行显式的序列化和反序列化。序列化即将结构化的数据转化成字节流,反序列化则反之。

2024-12-21 20:24:15 1231

原创 合并两个排序的数组

方法二中使用了一个临时数组,先将数据放到临时数组中,排序完成之后,再将数据放回数组A中。为了避免数据被覆盖的情况,可以使用一个临时数组,还可以使用从后向前的方法。4个判断分支还可以优化,4种分类情况可以分为两类,主要是情况2和情况3两类,情况1和情况2可以属于其中的一类。最先想到的一种方法,也是最基础、最直接的方法,就是将B中的数据追加到A数组中,然后排序。③在快速排序中,首先要选定一个值,然后要确定这个值在数组中的位置,也需要从左和从右向中间进行比较,也会用到双指针。

2024-12-08 08:47:28 463

原创 fastdds:编译、安装并运行helloworld

从INSTALLATION MANUAL这一节可以看出来,fastdds支持的操作系统包括linux、windows、qnx、MAC OS。

2024-11-30 21:37:19 3199

原创 leetcode 数组中第k个最大元素

给定一个整数数组,返回数组的第k个最大的元素。(1)很容易能想到,可以先对数组进行排序,排序之后,nums[size - k ]就是想要的结果。排序算法可以使用选择排序、交换排序、插入排序、堆排序、快速排序、归并排序。前3种排序算法的时间复杂度为O(n * n),后3种排序算法的事件复杂度是O(nlogn)。在实际使用中,常常使用堆排序或者快速排序,堆排序是选择排序的思想,快速排序是交换排序的思想。(2)使用堆排序或者快速排序,需要把数组整体排序完成吗?不需要。

2024-11-21 07:18:17 657

原创 fastdds基础:多播

支持多播和广播,这是udp相对于tcp的优势。因为tcp是面向连接的协议,面向连接的意思是一对一之间的连接,那么tcp就无法支持多播和广播。多播的应用比较广泛,比如视频会议、在线直播。在fastdds中也使用了多播,用多播来做writer和reader之间的发现,也叫服务发现。多播也叫组播。

2024-11-17 20:45:37 1622

原创 std::cout两个坑

使用std::cout打印char类型的指针,如果这个指针为空的话,那么会导致后边使用std::cout进行的打印都不显示。(2)打印空的char指针,会导致后边的std::cout打印都打印不出来。(3)打印空的int指针,没有影响,将空指针当成0打印了出来。(1)打印非空的char指针,执行正常。

2024-11-16 19:59:37 217

原创 posix timer使用入门

在c、c++开发中,如果使用定时器,我们经常会使用posix timer。posix timer使用较为灵活,本文介绍posix timer的使用。

2024-11-02 16:42:24 937

原创 自动驾驶性能优化时,非常有用的两个信息

自动驾驶的关键路径如下,传感器的数据发送给感知模块;感知模块根据传感器数据来确定车辆所处的环境,比如前方有没有障碍物,是不是和车道线保持着适当的距离等;感知处理之后的数据传递给规控模块,规控根据车辆当前所处的环境来规划车辆的路线和加减速等;最后规控的结果要发送到底盘/动力来做真正的执行。在自动驾驶的关键路径中,对确定性要求是非常高的,因为车辆是一个安全产品,一旦某个环节消耗的时间不符合确定性的要求,那么会造成比较大的影响。比如车辆前方有行人,那么车辆就需要及时刹停,不可延误。

2024-10-29 23:05:42 925

原创 一次使用LD_DEBUG定位问题的经历

在实际工作中,当遇到段错误,我们会很容易的想到这是非法访问了内存导致的,比如访问了已经释放的内存,访问数据越界,尝试写没有写权限的内存等。使用gdb进行调试,查看出异常的调用栈,往往可以定位到问题原因。但是有些时候,段错误问题的定位也没这么简单。本人在工作中就遇到了一个段错误的问题,问题原因不是那么直观,出问题的代码非常简单,直接按照常规的分析方法,很难分析出原因。往内存越界、内存没有权限这个方向分析无法定位问题。可执行文件直接依赖两个动态库,两个动态库有同名符号,这样编译可执行文件的时候无法编译通过。

2024-10-19 17:06:11 1402

原创 linux用户态条件变量和内核态完成变量

如果我们的线程要等一个条件满足之后才可以继续向下执行,这个条件不满足的话,就要等待这个条件。这种场景经常见到,比如我们使用recv接收网络数据的时候,或者使用epoll_wait来等待事件的时候,在默认情况下,recv和epoll_wait都会等到有数据或者事件到来才会返回。生产者和消费者的场景是条件变量典型的应用场景。一个队列,一个生产者,一个消费者,生产者向队列中生产数据,消费者从队列中消费数据。当队列满的时候,生产者就不能继续生产了,需要等有元素被消费之后才能继续生产;

2024-10-17 22:22:27 1118

原创 systemd使用入门

systemd负责管理整个操作系统,功能非常强大。我们在实际工作中,常常使用systemd来管理我们的服务。(1)想要开机之后自动启动,从而不需要每次开机之后都手动启动进程,可以通过systemd来实现。(2)如果我们要求进程异常崩溃之后要自动拉起来,可以通过systemd来实现。(3)我们有3个服务:a、b、c,其中服务b和c的启动依赖于服务a,只有服务a启动之后,服务b和c才可以启动,这样的依赖关系管理,我们也可以通过systemd来实现。

2024-09-28 16:10:07 1676

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除