APUE-信号部分

信号

什么是信号

信号提供的是一种处理异步事件的方法,有很多种信号,很多条件可以产生信号,对于进程来说,信号何时发生是无法预测的,进程只能保证当信号发生时做什么,有下面三种做法:

  1. 忽略信号:SIGKILL和SIGSTOP无法忽略;
  2. 捕捉信号:捕捉信号并调用指定函数,SIGKILL和SIGSTOP无法捕捉;
  3. 执行系统默认动作;

中断的系统调用

当执行一个慢速系统调用——可能使进程永远阻塞的系统调用——阻塞时,若捕捉到信号,则此系统调用被中断,出错返回并设置EINTR,有的系统调用会自动重启,有的不会,请注意。

阅读更多
APUE-进程部分

进程环境

程序的启动

内核执行C程序时,先调用启动例程,然后可执行程序文件将启动例程设置为起始地址,启动例程然后从内核获得命令行参数和环境变量,类似下面这样调用main函数:

1
exit(main(argc, argv));

退出函数

1
2
3
void exit(int status);
void _Exit(int status);
void _exit(int status);

这三个函数的区别:

  • exit()会对标准IO进行清洗,关闭所有IO流,并调用注册在atexit和on_exit里的函数(调用顺序与注册顺序相反,可以重复注册),然后调用_exit()。
  • _exit()直接返回内核,清理内存和进程。
  • _Exit()和_exit()等价,只不过前者是标准IO库里的,后者是系统调用。
阅读更多
APUE-文件部分

文件IO

相关函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 返回的文件描述符一定是最小的未用描述符数值
// at函数从fd相对路径打开文件
// at函数可避免TOCTTOU错误
int open(const char *path, int oflag, ...);
int openat(int fd, const char *path, int oflag, ...);

// 等同于open(path, O_WRONLY|O_CREAT|O_TRUNC, mode);
int creat(const char *path, mode_t mode);

// 关闭文件的同时会释放文件上的所有记录锁
int close(int fd);

// 设置文件偏移量,只更改偏移量,不引起I/O操作
off_t lseek(int fd, off_t offset, int whence);

// 返回读/写字节数
ssize_t read(int fd, void *buf, size_t nbytes);
ssize_t write(int fd, void *buf, size_t nbytes);

// 相当于先lseek后read/write,但是是原子操作
ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
ssize_t pwrite(int fd, void *buf, size_t nbytes, off_t offset);
阅读更多
UNP-网络编程进阶

第十二章 IPv4和IPv6

一图解释:

第十三章 守护进程和inetd

守护进程:在后台运行且不与任何终端关联的进程。

syslogd:这个守护进程创建Unix域数据报套接字绑定/dev/log,等待接受日志信息,不过推荐使用syslog函数。

阅读更多
UNP-网络编程基础

既然意向是后台开发,理应看看网络编程相关的书籍,这方面经典书籍应该就是UNP了,花了一个多星期时间看完了前两部分,感觉上手不难,但是知识比较杂,底层API比较多,有很多坑要注意,所以先总结一下,注意,略过了SCTP相关内容

第一章 本书简介

这一章简单介绍了一下网络编程,并用timeclient和timeserver程序引入了后面要讲的基本知识,然后介绍了一些历史和标准,本书的示例等等。

值得学习的是包裹函数的思想,将可能发生错误的函数用另一个函数包起来,并在这个函数里处理那个函数可能发生的错误,可以一定程度上简化程序的编写,并且也有利于程序的维护。

习题里提到一点,不同TCP对数据的处理是不同的,应当做好把数据看做字节流来处理的准备,直至到达数据流末尾。

阅读更多
vim命令整理

开始接触Linux时便有听说vim,之后在学习Linux命令的过程中就把vim学了学,但是之后就没怎么用过vim了。直到前段时间学习shell脚本时,一直用vim在终端里写shell脚本,熟悉了一些基础的vim命令,感受到vim编辑代码的高效。

平心而论,我是懒得去把vim配置成IDE的,我还是离不开IDE的……不过在IDE中装个vim插件,同时享受vim编辑的高效和IDE的便捷,我觉得还是很好的,于是觉得自己该补补vim的命令了,特此整理:

vim有多种模式,默认进入是命令模式,之后按a,o,i,c,s等可以进入插入模式,或是按v进入可视模式。按ESC退出插入或可视模式,如果你不知道现在在干什么,按两下ESC能保证你退回到初始的命令模式。

阅读更多
从零开始机器学习

机器学习的定义

作为机器学习领域的先驱,Arthur Samuel在 IBM Journal of Research and Development期刊上发表了一篇名为《Some Studies in Machine Learning Using the Game of Checkers》的论文中,将机器学习非正式定义为:“在不直接针对问题进行编程的情况下,赋予计算机学习能力的一个研究领域。”

而我认为机器学习是:我们在日常生活中,会遇到很多问题,大致分为两类,一类问题有确定的解法,比如说判断一个数是否是偶数,这种问题可以很清楚地用计算机编写程序并解决;另一类问题则没有固定的解法,比如说判断一个人说了什么,写了什么,因为这些问题的随机性很大,我们解决这些问题的方法,就是用大量的数据,采用一些训练方法,来训练计算机,使得计算机能够解决这些问题,而这个训练过程就称为机器学习。

阅读更多
Effective STL笔记

一.容器

第1条:慎重选择容器类型

C++提供了几种不同的容器供选择,他们之间各有差别,简单回顾一下:

  • 标准STL序列容器:vector、string、deque、list。
  • 标准STL关联容器:set、multiset、map、multimap。
  • 非标准序列容器:slist(单向链表)、rope(”重型”string)。
  • 非标准关联容器:hash_set、hash_multiset、hash_map、hash_multimap(均基于哈希表)。
  • vector<char>作为string的替代:第13条中讲述了何种条件下这种替代的意义。
  • vector作为标准关联容器的替代:第23条中阐述了,有时vector在运行时间和空间上都要优于标准关联容器。
  • 几种标准的非STL容器:数组、bitset、valarray、stack、queue、priority_queue,第16条中提及了一种“数组优于STL容器”的情形;第18条中解释了bitset比vector<bool>要好;另外,数组也可被用于STL算法,这是因为指针可被用作数组的迭代器。

如上,可做出的选择是很多的,这意味着我们在做出选择的时候要考虑多种因素,C++标准对“如何在vector、deque和list中做出选择”提供的建议:

vector、list和deque为程序员提供了不同的复杂性,使用时要对此做出权衡。vector是默认应使用的序列类型;当需要频繁地在序列中间做插入和删除操作时,应使用list;当大多数插入与删除操作发生在序列的头部和尾部时,deque是应考虑的数据结构。

以上建议如果是从算法复杂性考虑的话,是恰当的,但除此之外应考虑的还有很多。

STL有一种分类方法,这是对连续内存容器和基于节点的容器的区分:

  • 连续内存容器:把它的元素存放在一块或多块(动态分配的)内存中,每块内存中存有多个元素,当有新元素插入或已有元素被删除时,同一内存块中的其他元素要向前或向后移动,为新元素让出空间,或者填充被删除的元素。这种移动影响到效率(参见第5条,第14条)和异常安全性。标准的连续内存容器有vector、string和deque,非标准的rope也是一个连续内存容器。
  • 基于节点的容器:每一个(动态分配的)内存块中只存放一个元素。容器元素的插入或删除值只影响到指向节点的指针,而不影响节点本身的内容,所以当有插入或删除操作时,元素值不需要移动。表示链表的容器,如list和slist,是基于节点的;所有标准的关联容器也是如此(通常实现方式为平衡树);非标准的哈希容器使用不同的基于节点的实现,第25条可看到这一点。

有了以上术语基础,以下是选择容器时应考虑的一些问题:

阅读更多