自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 xdp 入门

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

2024-02-28 18:08:19 4348

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

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

2024-02-27 14:55:33 3402

原创 使用cgroup踩过的坑

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

2024-02-18 22:08:43 5251

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

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

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

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

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

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

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

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

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

原创 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 933

原创 stack smashing detected

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

2025-03-22 12:05:24 984

原创 leetcode:单词距离

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

2025-03-08 10:10:41 285

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

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

2025-03-05 21:35:01 462

原创 std::thread:join/detach

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

2025-03-02 15:18:05 412

原创 设计模式:代理模式

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

2025-02-16 17:58:07 437

原创 设计模式:状态模式

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

2025-02-16 12:10:36 1150

原创 linux内核网络分层概述

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

2024-12-22 09:43:32 852

原创 fastdds:idl

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

2024-12-21 20:24:15 1014

原创 合并两个排序的数组

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

2024-12-08 08:47:28 410

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

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

2024-11-30 21:37:19 1995

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

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

2024-11-21 07:18:17 552

原创 fastdds基础:多播

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

2024-11-17 20:45:37 1223

原创 std::cout打印空的char指针会出现未定义行为

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

2024-11-16 19:59:37 182

原创 posix timer使用入门

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

2024-11-02 16:42:24 787

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

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

2024-10-29 23:05:42 772

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

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

2024-10-19 17:06:11 1273

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

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

2024-10-17 22:22:27 1064

原创 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 1437

原创 linux下共享内存的3种使用方式

进程是资源封装的单位,内存就是进程所封装的资源的一种。一般情况下,进程间的内存是相互隔离的,也就是说一个进程不能访问另一个进程的内存。如果一个进程想要访问另一个进程的内存,那么必须要进过内核这个桥梁,这就是共享内存。在linux中,共享内存有3种方式,分别是POSIX接口,mmap以及system V风格的接口。本文分别介绍这3种共享内存的使用方式。在3种方式中,POSIX接口简洁易用,是最常使用的;system V易用性不是很好,很少使用。。

2024-09-21 11:10:36 1297

原创 c++类模板为什么不能编译到动态库中来使用

在使用c++的时候,我们习惯于将类的定义声明在头文件中,即.h文件中,将类函数的实现定义在源文件中,即.cpp文件。如果我们要提供的是一个动态库,那么这种方式更常用,使用动态库的时候,包含头文件,编译的时候链接动态库就可以了。

2024-09-15 12:02:51 560

原创 select、poll、epoll的区别

select、poll、epoll均为linux中的多路复用技术。3种技术出现的顺序是select、poll、epoll,3个版本反应了多路复用技术的迭代过程。我们现在开发网络应用时, 一般都会使用多路复用,很少有用一个线程来监听一个fd的,其中epoll又是最常使用的。关于epoll的实现和常见问题可以参考。当我们在使用epoll的时候,会想当然的认为这种技术是理所应当的,这就是多路复用技术应该的样子。殊不知,从select到poll再到epoll也经历了一定的过程,epoll并不是一开始就出现的。

2024-09-07 21:57:22 1144

原创 fork入门

如下是fork的典型问题。fork之后有3个分支,分别是pid等于0,pid大于0,pid小于0。如果我们不了解fork的话,那么肯定会认为这里的if else分支只会有一个分支被执行。而实际的执行结果是两个分支都执行了。fork返回之后就创建了一个子进程,父进程在fork返回之后继续向下执行;子进程同样也是从fork返回之后开始执行。对于父进程来说,返回值是子进程的进程号,对于子进程来说,返回值是0。fork创建一个进程,就类似于孕妈妈生孩子。将孕妈妈推进产房的时候是一个人,从产房出来的时候是两个人。

2024-08-31 22:16:33 1162

原创 linux中可执行文件为什么不能拷贝覆盖

如下的代码,使用 gcc hello.c -o hello, gcc hello.c -o hello1分别编译出两个可执行文件hello和hello1,然后执行hello,再执行cp hello1 hello,这样会报错。如果可执行文件没有被执行,那么是cp命令是可以执行成功的。可执行文件被执行的时候,通过execve系统调用来进行。对于一个普通的文件,假如有两个文件,分别是file和file1,我们使用 cp file1 file的方式使用file1的内容来覆盖file的内容,这样是可以的。

2024-07-07 10:55:57 381 1

原创 linux软链接和硬链接的区别

如下图所示,一开始有两个文件soft和hard。使用 ln -s soft soft1创建软链接,soft1是soft的软链接;使用ln hard hard1创建硬链接,hard1是hard的硬链接。可以看到软链接的文件类型和其它3个文件的文件类型是不一样的,软链接的文件类型是l开头的。

2024-07-07 10:08:18 454

原创 leetcode判断二分图

图的问题肯定要用到深度优先遍历或者广度优先遍历,但又不是单纯的深度优先遍历算法和广度优先遍历算法,而是需要在遍历的过程中加入与解决题目相关的逻辑。题干中说了,这个图可能不是连通图,这个提示有什么作用呢?很多时候我们接触的题目,图都是连通的,对于连通图来说,从一个点开始遍历,不管是深度优先还是广度优先,遍历一遍就可以把图中的所有点都遍历到;而对于非连通图来说,从一个点开始遍历,就无法将所有点都遍历一遍,这就需要针对每个点都进行一次遍历。

2024-07-06 14:21:22 391

原创 cgroup memory使用超过限制会怎样?

cgroup可以对一个进程或者一组进程使用的资源进行限制,可以限制的资源包括cpu、memory、io等。其中memory可以对内存资源进行限制,比如我们限制进程所能使用的内存最大是1G,那么当进程已经使用了1G的内存的时候,这个时候进程再申请内存会怎么样呢?内存使用超过限制的时候有如下两种结果:(1)默认情况下,内存使用超过限制,会oom(out of memory),oom的时候系统会使用SIGKILL信号将进程杀死。(2)cgroup中也可以进行配置,oom的时候不杀死进程,此时进程进入D状态。

2024-07-06 10:56:31 1867

原创 leetcode LRU 缓存

所以需要使用链表来表示缓存,当访问一个数据的时候需要将当前这个数据从原来的位置上删除,然后加到链表的头部,删除一个节点的话,需要将这个节点的前一个节点和下一个节点连接起来,如果使用单向链表的话,那么只能找到这个节点的下一个节点,找不到上一个节点,所以需要使用双向链表。(6)向缓存中放入数据 1,此时缓存是满的,所以需要先淘汰一个数据,从访问时间来看,最后一次访问 50 的间隔时间最长,也就是排在最右边的数据,所以将 50 淘汰,其它数据向后移动,将新数据 1 放入最左边的位置。

2024-06-15 08:36:21 866

原创 error while loading shared libraries 找不到动态库问题如何解决

在使用 c 或 c++ 开发应用时,在启动程序时,有时会遇到这个错误,找不到动态库。这个时候,我们使用 ldd 来查看,发现可执行文件依赖的动态库显示为 not found。

2024-06-10 11:04:58 863

原创 system 和 exec 的区别

在 linux 中,使用 system 和 exec 都可以执行一个程序或者执行一个命令。两者的区别如下:system 中创建了一个子进程,在子进程中执行用户的命令,子进程执行完毕之后,system 会返回。exec 不会创建子进程,而是直接用 exec 要执行的进程来代替当前的进程,并且如果在执行过程中没有出现错误,那么 exec 是不会返回的,调用 exec 的进程永远也回不来了。

2024-06-09 19:44:03 1073

原创 leetcode 数组排序

leetcode:排序算法包括基础的选择排序、插入排序、交换排序;也包括快速排序,堆排序,归并排序等。其中快速排序是交换排序的升级版;堆排序是选择排序的升级版。那插入排序有没有升级版呢,也是有的,是希尔排序,但是希尔排序的思想不好理解,所以本文中不涉及希尔排序。选择排序,插入排序,交换排序属于基础排序算法,时间复杂度是O(n * n)。快速排序和堆排序的时间复杂度是 O(nlogn)。

2024-06-09 12:36:23 1006

原创 leetcode 所有可能的路径(图的遍历:深度优先和广度优先)

对于无向图来说,图中的边没有方向,两个节点之间只可能存在一条边,比如 0 和 1 之间的边,因为是无向图,这条边可以表示从 0 到 1 的边,也可以表示从 1 到 0 的边。当对图做遍历时,如果图是连通的,那么从一个节点开始,遍历一次,就能将图中所有的节点遍历一遍,所以遍历一次就可以了。连通图,指的是从一个节点出发沿着边进行遍历,能把图中的节点都遍历到的图。有环图说的是从一个节点开始遍历,在遍历过程中还能遍历到这个节点的图,除了开始节点和结束节点是相同的,其它节点不能重复出现,并且路径长度大于 2。

2024-06-08 14:05:29 1212

原创 性能优化随笔(一)

在软件开发过程中,一般要先实现功能方面的需求,功能方面的需求开发完毕之后,往往会考虑性能方面的优化。在业务发展的初期,性能往往能满足使用的需求,这时性能优化不是必不可少的。随着业务的发展,软件复杂度的提高,性能有时会成为瓶颈,这时性能优化是必须要做的工作。

2024-06-02 20:43:00 1744 3

原创 回文串算法题

回文串是一个正着读和反着读顺序一样的字符串。"aba" 是回文串,"abba" 是回文串,"abc" 不是回文串。回文串的题目,都要使用一个基本的逻辑,就是判断当前这个字符串是不是回文串。以 c++ 为例,代码如下。这种方法也可以称为双指针法,两个指针从字符串的两端向中间遍历每个字符,如果中间发现两个字符不相同,则不是回文字符串;遍历到最后,说明是回文串。双指针法,在其它数据结构题目中也会用到,比如链表中会用到快慢指针,也属于双指针。

2024-06-02 10:47:38 1126

空空如也

空空如也

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

TA关注的人

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