<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[gnr_123的专栏]]></title><description><![CDATA[]]></description><link>https://blog.youkuaiyun.com/gnr_123</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; gnr_123]]></copyright><item><title><![CDATA[C++实现插件化开发]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/122646854</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/122646854</guid><author>gnr_123</author><pubDate>Sun, 23 Jan 2022 02:15:46 +0800</pubDate><description><![CDATA[产品开发中，为了降低功能增加或变更的成本，在系统设计上就要有可扩展以及可替换的考虑，功能插件化是为软件系统增加扩展点的一种实用方法。

最近在翻vsomeip代码的时候关注到了里面的插件功能实现，这篇文章简要说明一下。

插件实现的简易框架就像下面这张图：





下面是代码示例，大部分内容都写到注释了，这张图就不再一一解释。


//定义插件的公共接口
class Plugin {
public:
  virtual std::string GetName() = 0;
  virtual i...]]></description><category></category></item><item><title><![CDATA[读《把时间当做朋友》]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/119769308</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/119769308</guid><author>gnr_123</author><pubDate>Wed, 18 Aug 2021 00:13:55 +0800</pubDate><description><![CDATA[《把时间当做朋友》是李笑来的一本书，现在最新的是第三版，虽然作者本人备受争议，但书本身值得一读，在刚工作那几年，这本书给过我很多启发。

这是一本关于个体提升的书，涉及的面很广，例如做事的方法、时间统计、任务规划、如何更好学习、思考和交流等，但相对来说在具体的一个方面就不会那么深入。书写的很生动，不晦涩，即使没有大片连续的时间，随手拿起来读几页也可以引发思考，如果在具体的某一方面有兴趣，可以按图索骥去多找几本内容上更深入的书来看，获得更深入的认知，因此这是一本非常适合初入职场的同学来看的书。对于工作...]]></description><category></category></item><item><title><![CDATA[Linux DMA驱动框架]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/118004319</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/118004319</guid><author>gnr_123</author><pubDate>Thu, 17 Jun 2021 23:49:35 +0800</pubDate><description><![CDATA[DMA（Direct Memory Access），直接内存访问，这里的直接是和需要CPU参与的内存访问相对的概念，在我们写程序的时候经常会遇到这样的场景：


	将数据从一片内存搬运到另一片内存
	
	
	持续不断从IO设备读取数据到内存
	
	
	将大量数据不断写入IO设备
	
这样的活儿CPU当然能干，不过其他的事情就只能推后再处理，毕竟CPU最擅长的还是串行的逻辑，如果能有一个外设，我们告诉它数据存储的地址和长度，再告诉它从哪里搬运到哪里，它就能任劳任怨的去干，最好干完了能再通知CPU一声，那岂..]]></description><category></category></item><item><title><![CDATA[Linux内核同步机制RT-mutex]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/116772656</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/116772656</guid><author>gnr_123</author><pubDate>Fri, 14 May 2021 00:21:32 +0800</pubDate><description><![CDATA[Linux内核打上了PREEMPT_RT补丁之后支持完全可抢占，中断处理将线程化，线程化之后允许抢占和休眠，因此原本中断处理中使用的spinlock，实际上也将替换为使用rt_mutex。

互斥量加上了rt的前缀，主要是因为支持优先级继承，防止优先级翻转造成的高优先级任务等待时间的不确定性。优先级翻转可以通过下面这张图来理解。



图中3个进程的优先级A&gt;B&gt;C。假设低优先级的进程C和高优先级进程A竞争共享资源，而C先持有了lock，A只能阻塞等待C释放lock。假如A阻塞期间有更高优先..]]></description><category></category></item><item><title><![CDATA[linux内核同步机制-RCU(4)]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/115054801</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/115054801</guid><author>gnr_123</author><pubDate>Sun, 21 Mar 2021 20:11:03 +0800</pubDate><description><![CDATA[上一篇文章我们搞清楚了CPU如何检测QS状态，如何上报QS状态，GP状态机管理，也就知道GP何时结束，进而知道了旧数据内存是何时被回收的，这次我们来看RCU的订阅发布机制。

所谓的订阅和发布在API上的体现是rcu_assign_pointer和rcu_dereference，从接口的名字上可以看出，订阅和发布实际上指的的是指针赋值和解引用，也就是新的数据对于reader的可见性。在C语言里指针赋值用等号就可以实现，为什么要大费周章的用两个函数包装起来呢？我们先来看一段代码。


struct dat..]]></description><category></category></item><item><title><![CDATA[linux内核同步机制-RCU（3）]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/114783204</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/114783204</guid><author>gnr_123</author><pubDate>Sun, 14 Mar 2021 12:50:57 +0800</pubDate><description><![CDATA[在正式开始之前，我们来回顾两个比较重要的概念，grace period和quiescent state.


grace period的确定在rcu里很重要，它代表了读操作是否完成，也就是是否退出了临界区。在使用rcu时我们约定不允许阻塞（休眠）、切换到用户态和进入idle，并且把这几种不应该出现的状态起了个名字叫quiescent state（静止状态），当一个cpu进入quiescent state我们就认为这个cpu已经退出了临界区，当所有cpu都经历过quiescent state，我们就可以判..]]></description><category></category></item><item><title><![CDATA[linux内核同步机制-RCU（2）]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/113443288</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/113443288</guid><author>gnr_123</author><pubDate>Sat, 30 Jan 2021 17:34:34 +0800</pubDate><description><![CDATA[在上一篇文章里，我们通过几段代码初步认识了RCU，也知道了RCU有下面几个特点：


	在读操作的代码段，RCU和读写锁几乎一样，但不会被写操作阻塞
	
	
	RCU主要用于保证指针数据的同步
	
	
	在写操作时，RCU分为两步，将指针指向新内存，推迟回收旧内存
	
	
	由于在某一时间段内会同时存在新数据和旧数据，所以只适用于不严格要求数据同步的场景
	
这次我们就就到内核代码里去看看RCU到底是怎么实现的，首先我们要找到linux内核里RCU都有哪些文件，大家可以在下面这张图里看到，需要提前...]]></description><category></category></item><item><title><![CDATA[linux内核同步机制-RCU（1）]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/113208054</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/113208054</guid><author>gnr_123</author><pubDate>Wed, 27 Jan 2021 00:23:48 +0800</pubDate><description><![CDATA[Linux内核里的同步机制众多，RCU（read-copy update）可以说是实现上比较复杂的一种了，比较适合用在读操作很多而写操作极少的情况，可以用来替代读写锁。RCU的实现本质上是一种trade-off，为了让读操作的开销尽可能的小，写操作的完成可以被推迟。

我们先通过几个内核中的例子来了解一下。

首先来看RCU在读操作方面是如何替代读锁的，观察下面的代码我们发现在使用上几乎没有什么差别，只是把read_lock()/read_unlock()换成了rcu_read_lock()/rcu_r..]]></description><category></category></item><item><title><![CDATA[你的程序是如何开始运行的？]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/111305650</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/111305650</guid><author>gnr_123</author><pubDate>Wed, 16 Dec 2020 23:42:12 +0800</pubDate><description><![CDATA[每个等电梯的程序员都想过电梯调度算法，每个的程序员也都想过，我每天写的bug程序到底是怎么运行起来的呢？

今天我们就来聊一聊这个话题，不过程序也分很多种，例如按照运行环境就可以分linux、windows、嵌入式的RTOS、裸机，按照编程语言又可以分成会被编译成目标机机器码的（例如C/C++），会被编译成字节码的（例如java），由解释器解释执行的（例如python，即使你没用过也一定在微信里见过它的广告），简直数都数不过来，所以更具体的说，今天我们要聊的是linux下的C/C++程序是如何被执行的。

]]></description><category></category></item><item><title><![CDATA[嵌入式中的时间和定时]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/110153421</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/110153421</guid><author>gnr_123</author><pubDate>Thu, 26 Nov 2020 01:03:17 +0800</pubDate><description><![CDATA[开发软件经常会用到时间，不同的场合用到的时间也不尽相同，有时候我们需要的是年月日时分秒这样很容易理解的格式，也有时候我们只是想知道系统开机了之后运行了多久，还有的时候我们不需要知道具体时间，只是想像设定一个闹钟一样，时间到了叫我干活就行。

在操作系统的内核里也一样，没了时间做基础，什么时间片、周期调度、延迟处理都没办法实现，这些关于时间的服务（也可以叫功能），总结下来是下面这两类：


	获取时间
	
	
	定时服务
	
那这两个功能是怎么实现的呢？世上没有免费的午餐，想用到什么功能，就得有相应的软硬..]]></description><category></category></item><item><title><![CDATA[嵌入式编程语言]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/109699536</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/109699536</guid><author>gnr_123</author><pubDate>Sun, 15 Nov 2020 01:10:53 +0800</pubDate><description><![CDATA[嵌入式开发几乎离不开C/C++，虽然在一些嵌入式linux的开发场景可以选python、java，不过也需要BSP和SDK的支持，像操作系统移植、驱动开发几乎就是C的天下，最近有传闻rust也能开发linux内核模块了，但距离大规模使用看上去还很远，C++因为提供了比C更现代的面向对象和模板等特性，并且有大量开源代码库，在嵌入式linux领域也有大量的使用。如果是单片机开发，不管是裸机还是RTOS，C基本就是不二选择了，这么多年下来，不管是互联网资源还是各大公司的技术积累，C和C++都是最多的，总而言之呢，]]></description><category></category></item><item><title><![CDATA[spdlog中的完美转发]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/109523861</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/109523861</guid><author>gnr_123</author><pubDate>Fri, 06 Nov 2020 00:46:48 +0800</pubDate><description><![CDATA[spdlog是一个c++实现的日志库，代码中大量使用了c++11的特性，并且只需要头文件就可以使用，十分值得使用和研究。

下面这段代码是spdlog中的一个工厂函数，用来创建一个新的logger，里面用到了c++11之后才支持的完美转发。


template&lt;typename Sink, typename... SinkArgs&gt;
static std::shared_ptr&lt;spdlog::logger&gt; create(std::string logger_na...]]></description><category></category></item><item><title><![CDATA[如何为你的硬件开发Simulink Toolbox(6)]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/107828284</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/107828284</guid><author>gnr_123</author><pubDate>Wed, 05 Aug 2020 23:58:37 +0800</pubDate><description><![CDATA[看过上一篇文章会知道，我们已经可以生成模型代码和主程序，但还没有进行编译，今天我们对Toolbox进行改造，在点击Build之后除了生成C文件，还将自动的编译生成bin文件。
在此之前，我已经为我的STM32硬件准备好一个完整的工程，把里面的主程序删除掉，剩下的是：

Startup，STM32的启动文件
Libraries，里面包含外设驱动头文件和STM32F10xR_V3.0.lib
Project，这里只放了一个sct文件

首先我们修改mytarget.tlc这个系统tlc文件，增加设置代码生成路.]]></description><category></category></item><item><title><![CDATA[如何为你的硬件开发Simulink Toolbox(5)]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/107454895</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/107454895</guid><author>gnr_123</author><pubDate>Mon, 20 Jul 2020 01:05:17 +0800</pubDate><description><![CDATA[上次我们写了一个可以自动化配置模型选项的Block，双击它即可完成模型的配置，即配置了模型的基本信息，也配置了系统tlc、makefile模板、代码模板等和代码生成关系紧密的几个文件。
这次我们关注的是mytarget_proc.tlc这两个文件，它对应的是ERTCustomFileTemplate这个选项，可以用它来生成自定义的main函数，真正和我们的硬件发生联系。
翻箱倒柜从灰尘堆里的STM32开发板找出来，硬件我们就用他了，编译器用Keil，大家如果使用不同硬件和编译器也无所谓，根据自己的情况进行调]]></description><category></category></item><item><title><![CDATA[如何为你的硬件开发Simulink Toolbox(4)]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/106990150</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/106990150</guid><author>gnr_123</author><pubDate>Sat, 27 Jun 2020 23:28:38 +0800</pubDate><description><![CDATA[这次我们从实现一个对模型选项进行设置的block开始，串联起几个Simulink Toolbox的控制文件，并写一个简单的S-Function文件，Simulink本身也提供了类似的block，例如下面这几个。



我们不使用它生成任何的代码，而是利用Simulink的callback机制和m语言，自动化完成模型选项的设置。

首先我们拖一个Simulink-&gt;User Defined Functions-&gt;S-Function到我们的libaray，修改成下面的样子。



首先Crea..]]></description><category></category></item><item><title><![CDATA[如何为你的硬件开发Simulink Toolbox(3)]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/106605204</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/106605204</guid><author>gnr_123</author><pubDate>Sun, 07 Jun 2020 18:20:00 +0800</pubDate><description><![CDATA[在Simulink Toolbox中，需要为自定义开发的block写S-Function，我们使用的C语言编写，也叫C Mex S-Function，C语言编写的S-Function仿真速度快，也可以调用具体的硬件驱动和使用已有的C库，功能十分强大，我们的目标是为硬件编写Toolbox，S-Function的主要功能是将自定义Block的参数传递给TLC，让TLC可以生产和我们的硬件匹配的代码。
C Mex S-Function Matlab不能直接使用，需要先编译成mex文件，这次我们先做一些准备工作，安]]></description><category></category></item><item><title><![CDATA[C++使用正则表达式]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/106449049</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/106449049</guid><author>gnr_123</author><pubDate>Sat, 30 May 2020 23:21:42 +0800</pubDate><description><![CDATA[C++使用正则表达式
正则表达式在文本的查找和替换方面十分强大，最近恰巧用到，记录如下。
使用的语言是C++，需要包含regex头文件，下面的代码是对linux系统路径的判别，我们假定路径都是下面这样的：

./abcd
…/abcd
/abcd/efg

#include &lt;stdio.h&gt;

#include &lt;string&gt;
#include &lt;regex&gt;
#include &lt;exception&gt;
#include &lt;iostream&gt;
.]]></description><category></category></item><item><title><![CDATA[linux加载动态链接库so文件]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/106225507</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/106225507</guid><author>gnr_123</author><pubDate>Tue, 19 May 2020 23:18:30 +0800</pubDate><description><![CDATA[有时出于软件灵活性的考虑，我们不会在编译阶段直接关联so文件，而是通过dlopen等几个函数调用动态加载，主要用到的函数接口有：


	dlopen
	
	
	dlsym
	
	
	dlclose
	
需要包含的头文件是dlfcn.h，在编译时需要加上-ldl。下面是一个简单的例子，首先我们写一个lib_printnumber函数，只是将传入的参数打印出来。


#include &lt;stdio.h&gt;
​
void lib_printnumber(int arg)
{
  printf("...]]></description><category></category></item><item><title><![CDATA[如何为你的硬件开发Simulink Toolbox(2)]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/106184532</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/106184532</guid><author>gnr_123</author><pubDate>Mon, 18 May 2020 00:27:09 +0800</pubDate><description><![CDATA[今天我们开始动手开发一个Simulink Toolbox。



创建文件目录

首先我们创建Simulink Toolbox的目录结构，这个不需要完全一样，可以按照大家的习惯，我这里创建之后像下面这样：



创建Simulink library文件

在Matlab里点开Simulink，新建一个Blank Library，保存为mytargetlib.slx文件。



然后从Simulink Browser里拖进一个S-Function文件，这次我们什么都不做，只是把它放到我们的Library...]]></description><category></category></item><item><title><![CDATA[如何为CentOS更新内核]]></title><link>https://blog.youkuaiyun.com/gnr_123/article/details/105942004</link><guid>https://blog.youkuaiyun.com/gnr_123/article/details/105942004</guid><author>gnr_123</author><pubDate>Wed, 06 May 2020 00:15:32 +0800</pubDate><description><![CDATA[linux作为一个通用操作系统，更注重综合的性能表现，对于一些系统响应时间确定性/实时性要求严格的场合并不能满足。为了在追求系统实时性的同时又能够利用到linux生态丰富的软件资源、我们可以从硬件、系统内核、系统配置、应用等各个层面对其进行优化。

这篇文章主要是关于如何为CentOS/Ubuntu更新为实时内核，网络上关于给内核打实时补丁和安装方面的文章可以搜索到很多，其过程大同小异，下面一张图...]]></description><category></category></item></channel></rss>