陶庵夢憶 夢憶序 陶庵國破家亡,無所歸止,披髮入山,駴駴為野人。故舊見之,如毒藥猛獸,愕窒不敢與接。作自輓詩,每欲引決,因《石匱書》未成,尚視息人世,然瓶粟屢罄,不能舉火,始知首陽二老,直頭餓死,不食周粟,還是後人粧點語也。 飢餓之餘,好弄筆墨,因思昔人生長王謝,頗事豪華,今日罹此果報:以笠報顱,以簣報踵,仇簪履也;以衲報裘,以薴報絺,仇輕煖也;以藿報肉,以糲報粻,仇甘旨也;以薦報床,...
Linux 60秒性能分析
本文主要参考Netflix的技术博客。 在读Brendan Gregg的BPF Performance Tools,其中提到他和Nefilx性能团队曾经发表的一篇关于性能分析的文章1,讲述了对一个新Linux系统性能分析的前60秒应该进行哪些步骤。 尽管国内有不少网站已经翻译转载过那篇原始博文,但为了加深自己的印象,还是重新将相关内容转述一下(也算一种重复造轮子吧www)。 简...
C语言的翻译阶段
本文基于C17(C18)版本。 一个C语言程序不需要全部在同一时间翻译。程序的文本被保存在称为源文件(或预处理文件)的单元中。一个源文件连同所有头文件和通过预处理指令#include包含的源文件被称为预处理的翻译单元。在预处理之后,一个预处理翻译单元被称为翻译单元。 以前翻译过的翻译单元可以单独保存,也可以保存在库中。一个程序的独立翻译单元通过(例如)调用其标识符有外部链接的函数...
C语言编译期的静态断言
本文基于C17(C18)版本。相关内容在后续版本中可能有较大变化,文中对部分有变化的情况做了说明。 相比于C++在编译期(complie-time)的强大能力(如C++的模板元编程是图灵完备的,而这正是在编译期进行的),C语言要逊色许多,但我们仍然能够在编译期进行基本的计算和断言工作,无论是将计算移至编译期所带来的,从而能够将某些运行时才能发现的问题。 常量表达式 首先介绍常量...
原子操作和内存序
本文描述基于C、C++中的atomic库。 锁无关 在多线程程序设计中,为了解决数据竞争问题,引入了锁来解决相应问题。但频繁的使用锁,往往会花费大量时间在线程的状态切换上,为了降低系统开销提升性能,人们希望在避免使用锁的情况下编写程序,这也被称作锁无关(lock-free)的程序设计。 原子操作 原子操作类别 读 写 读-改-写 指令重排 编写程序的时候,...
file命令是如何工作的?
file命令通过如下三个步骤判断文件类型。 检查文件系统(filesystem tests) 先通过stat(2)查看是否为本系统通用的类型(如目录),头文件<sys/stat.h>中保存有相关定义。 检查魔数(magic tests) 许多类型的文件开头是特定的魔数,魔数和文件的对应关系通常会记录在/etc/magic或/usr/share/misc/magic。 检查语...
C语言中的宏
C语言中,宏几乎随处可见,宏将标识符转换成相应的代码段,能够起到复用代码,防止霰弹式样修改的作用。 但宏也是危险的,宏由预处理器进行处理,从而导致编译器和程序员所看见的代码存在区别,这种不直观性往往是各类bug的根源,许多代码规范都强调了宏的危险性。 尽管如此,宏的许多特性,如串化(stringifying)、连接(concatenation)等在C语言中的作用却是无可替代的。作为C程序...
Go语言中的函数
本文基于Go 1.19版本。 声明 Go语言中,函数的声明由名字、形参列表、返回列表(可选)和函数体构成,注意Go对代码格式要求比较严格: func name(parameter-list) (result-list) { body } 声明的组成成分 函数的名字和其他名字有着同样的规则,由字母或下划线开头,后面可以跟任意数量的字符、数字和下划线,并且区分大小写。 ...
POSIX定时器和看门狗实现
创建POSIX定时器 可以通过timer_create函数创建POSIX定时器,其中timer_create函数声明如下; #include <signal.h> /* Definition of SIGEV_* constants */ #include <time.h> int timer_create(clockid_t clockid...
一切皆对象:Python中的对象概念
对象是Python中对数据的抽象。Python程序中的所有数据都是由对象或对象间关系来表示的。 Python中,一切皆对象。 本文基于Python 3.10。 对象的组成 在Python中,任何对象都有各自的标识号(identity)、类型(type)和值(value)。 标识号 一个对象被创建后,其标识号就绝不会改变。通过id()函数可以返回代表对象标识号的整数,is运...