阅读《Linux高性能服务器》的笔记
一 API
-
fork系统调用
#include <sys/types.h> #include <unistd.h> pid_t fork(void); /* 返回值: 0,表示当前在子进程 >0,子进程ID,表示当前在父进程 -1:失败,设置errno */
- 子进程代码与父进程相同。
- 写时复制(堆数据、栈数据、静态数据)。先是缺页中断,然后操作系统给子进程分配内存并复制父进程数据。
- 创建子进程后,父进程中打开的文件描述符默认在子进程中也是打开的。
-
exec系列系统调用
- 参数
- path:可执行文件的完整路径
- file:文件名,具体位置在环境变量PATH中搜索
- arg:可变参数
- argv:参数数组,都会传递给新程序的main函数
- envp:设置新程序的环境变量,不设置就用全局变量environ
- 返回值
- 成功,不返回,直接新程序
- 失败,返回-1,设置errno
- exec函数不会关闭原程序打开的文件描述符,除非该文件描述符设置了SOCK_CLOEXEC
二 处理僵尸进程
-
僵尸态
- 在子进程运行结束后,父进程读取其退出状态之前,该子进程处于僵尸态。
- 父进程结束或异常终止,子进程继续运行。此时子进程的PPID设置为1(init进程)
-
API
#include <sys/types.h> #include <sys/wait.h> pid_t wait(int* stat_loc); /* 阻塞进程,直到该进程的某个子进程结束运行为止。 stat_loc:保存结束运行的子进程的退出状态 返回值:结束运行的子进程的PID */ pid_t waitpid(pid_t pid, int* stat_loc, int options) /* 只等待pid进程 pid: -1,和wait相同 >0,指定子进程 stat_loc:与wait的相同 options: WNOHANG:非阻塞,pid指定的子进程没结束或意外结束,返回0 子正常退出,返回子进程PID 调用失败,返回-1,设置errno */
- SIGCHILD信号的典型处理函数
-
对waitpid而言,最好在某个进程退出后再调用。
-
通过SIGHUP信号,父进程能够直到子进程退出了。
static void handle_child(int sig) { pid_t pid; int stat; while((pid = waitpid(-1, &stat, WNOHANG)) > 0)) { //对结束的子进程进行善后处理 } }
-
三 管道
- 概念
- 进程间通信(父子进程等有关联的两个进程)
- 父子进程间传递数据。
- 父进程和子进程必须右一个关闭fd[0],另一个关闭fd[1]
- 父子进程实现双向数据传输,需要两个管道
- socketpair(),创建一个全双工管道
四 信号量
- 概念
- 对于公共资源,只能一个进程访问
- PV操作
- 信号量SV
- P操作,SV>0,SV—;SV==0,挂起进程
- V操作,有进程等待,唤醒;无等待,SV++
- semget系统调用
-
API
#include <sys/sem.h> int semget(key_t key, int num_sems, int sem_flags); /* 获取或创建信号量集 key:标识全局唯一的信号集。 num_sems:创建/获取的新信号量数量。 创建:必须指定 获取:0 sem_flags:信号量权限,和open的mode参数相同 返回值: >0,信号量标识符 -1,失败,设置errno */
-
-
semop系统调用
- 改变信号量的值,即执行P、V操作
-
semctl系统调用
- 允许调用者对信号量进行直接控制
五 共享内存
-
概念
- 最高效的IPC机制,不涉及进程间任何数据传输。
- 必须使用其他辅助手段同步进程对共享内存的访问。
-
shmget系统调用
#include <sys/shm.h> int shmget(ket_t key, size_t size, int shmflg); /* key:标识全局唯一的共享内存 size:共享内存的大小。 创建:必须指定 获取:0 shmflg:共享内存权限 返回值: >0,共享内存标识符 -1,失败,设置errno */
-
shmat和shmdt系统调用
#include <sys/shm.h> void* shmat(int shm_id, const void* shm_addr, int shmflg); /* 关联共享内存到地址空间 shm_id:shmget的返回值 shm_addr:指定将共享内存关联到进程的哪块位置,一般为NULL,系统自己分配 shmflg: SHM_RDONLY。进程只能读取共享内存的内容。没指定,默认可以读写(必须在创建共享内存的时候指定其读写权限) 返回值: 失败:(void*)-1,设置errno 成功:共享内存被关联到的地址 */ int shmdt(const void* shm_addr); /* 分离 shm_addr:shmat的返回值 */
-
shmctl系统调用
#include <sys/shm.h> int shmctl(int shm_id, int command, struct shmid_ds* buf); /* shm_id:shmget的返回值 command: IPC_RMID:在共享内存打上删除的标记,当最后一个进程调用shmdt时,该共享内存就删除了 */