哈喽,我是老吴,继续记录我的学习心得。
一、构建思维组块
构建组块(chunking):
就是利用一些概念,组合起信息碎片,这是一种心智上的飞跃。
构建组块的方法:
把注意力集中在需要组块的信息上 。思维就像章鱼触手,一旦分心就无法抓紧。
把基本概念打包成组块,然后理解这个基本概念。专注和发散模式的交替思考,总能理清头绪,把握概念。
获取背景信息,不仅是知道如何进行组块,还要知道何时何地如何使用该组块。
学习活动包括 “以上至下、从下至上” 两个方向:
从上至下的宏观学习,和从下至上的组块活动,两个过程对熟练掌握知识都有重要作用。
应用到软件开发上:
大多数编程书里是教授的都是大量的细微的知识点,我们需要先把这些非常小的知识点体系化,形成多个组块,这是从下至上的组块活动。观察现有的优秀软件 (一般是开源软件) 是如何使用组块的,这是从上至下的宏观学习。
另外,学习软件开发要学会抽象,写代码是抽象再组合,而读代码则是分解出一个个小的组块。
二、..Linux系统编程 / 分析开源软件 Triggerhappy / (2) 把握核心流程
正文目录:
1. 分解 thd.c / start_readers()
1.1 thd.c / start_readers() 的作用
1.2 thd.c / start_readers() 的内容
1) 根据命令行参数,判断是否需要打开 socket
2) 将命令行中指定的输入设备添加到设备链表中
3) 根据命令行参数,决定是否成为守护进程 (daemon)
4) 根据命令行参数,决定是否创建 pidfile
5) 真正开始监控设备并处理事件
写作目的:
通过分析开源软件 Triggerhappy,练习 Linux 系统编程。
测试环境:
Ubuntu 16.04
Gcc 5.4.0
1. 分解 thd.c / start_readers()
1.1 thd.c / start_readers() 的作用
1) 作用:
启动读进程,虽然该程序是单进程的,复数 readers 可能是作者觉得有机会使用多线程吧。
2) 使用者:
私有函数,只有 thd.c / main() 会调用。
1.2 thd.c / start_readers() 的内容
1) 根据命令行参数,判断是否需要打开 socket:
/* open command pipe */
if (cmd_file) {
cmd_fd = bind_cmdsocket(cmd_file);
if (cmd_fd < 0) {
return 1;
}
}
cmd_file 对应参数 -s:
$ man thd
--socket file
Open a unix domain socket at file; this socket can be used to send commands to the running daemon (by
using the program th-cmd), e.g. for adding or removing devices.
这里的 socket 类型是 UNIX domain socket (AF_UNIX),该 socket 允许位于同一主机系统上的进程之间相互通信的。
bind_cmdsocket() 的实现位于 cmdsocket.c,thd 和 thd-cmd 会共用 cmdsocket.c 来通过 socket 通讯以动态地增减要监控的输入设备.
后续再来细看 cmdsocket.c 的内容,分析该文件可以学习 UNIX domain socket 相关的知识。
2) 将命令行中指定的输入设备添加到设备链表中:
/* add every device file supplied on command line */
for (i=start; i<argc; i++)
add_device( dev, -1, grab_dev, tag_dev );
thd 要监控的设备可以从2个地方指定:1. 命令行参数,2. glob device,这里处理的是情况1。
add_device() 的实现位于 devices.c, 该文件通过链表 (device *device_list) 来管理所有要监控的输入设备,肯定会有这些操作:增加 (add_device)、删除 ( remove_device )、遍历 (for_each_device)。
后续再来细看 devices.c 的内容,分析该文件可以学习到数据结构链表相关的知识。
2) 将 glob device 指定的输入设备添加到设备链表中:
/* check device glob */
glob_t globbuf;
glob(dev_glob, GLOB_NOSORT, NULL, &globbuf);
for (i=0; i<globbuf.gl_pathc; i++)
add_device(globbuf.gl_pathv[i], -1, grab_dev, tag_dev);
glob device 是什么?
$ man thd
--deviceglob pattern
Open device files matching the glob pattern.
glob 库函数用于 Linux 文件系统中路径名称的模式匹配, 看来是用来处理类似 /dev/input/event* 的情况。
3) 根据命令行参数,决定是否成为守护进程 (daemon):
if (run_as_daemon)
daemon(0,0);
什么是 daemon?
daemon 运行在后台,不与任何控制终端相关联。守护进程通常在系统启动时就运行,它们以 root 用户或者其他特殊的用户运行,并处理一些系统级的任务。
daemon 的两个基本要求:1. 必须作为 init 进程的子进程运行,2. 不与任何控制终端交互。
GNU C库提供了一个非标准的 daemon()函数,它将调用者变成一个 daemon,thd 就使用了该函数。
4) 根据命令行参数,决定是否创建 pidfile
if (pidfile)
write_pidfile( pidfile );
write_pidfile() 是 thd.c 的私有函数。
pidfile 为文本文件,一般内容只有一行, 记录了该进程的 PID。
它的作用是防止进程启动多个副本。
5) 真正开始监控设备并处理事件:
process_events();
process_events() 是 thd.c 的私有函数。
接下来需要重点分析该函数。
鉴于大多数人的注意力无法在一篇文章里上集中太久,更多的内容请大家先自行去阅读吧,不是自己理解到的东西是消化不了的。有机会的话我会把更多的分析心得放在后面的文章。
总结一下,接下来需要跟进的事情:
分析 thd.c / process_events();
分析 thd.c / reload_triggerfile()
这么看来,目前的任务还比较轻松。
三、思考技术,也要思考人生
学习技术,更要学习如何生活。
你和我各有一个苹果,如果我们交换苹果的话,我们还是只有一个苹果。但当你和我各有一个想法,我们交换想法的话,我们就都有两个想法了。
对 嵌入式系统 (Linux、RTOS、OpenWrt、Android) 和 开源软件 感兴趣,想和更多人互相交流学习,请关注公众号:嵌入式Hacker,一起来学习吧。
无论是关注或转发,还是打赏,都是对作者莫大的支持。觉得文章对你有价值的话,不妨点个 在看和点赞 哦。
ps:
欢迎加入我的微信群:加我,我拉你进群,暗号(加群)。
祝各位工作顺利,家庭幸福,财源滚滚~