Linux高性能服务器编程(第二篇 第13-15章)——阅读笔记

Linux高性能服务器编程(第二篇 深入解析高性能服务器编程)


第13章 多进程编程

1. fork系统调用

#include <sys/types.h>
#include <unistd.h>
// 每次调用返回两次
// 父进程中返回子进程pid,子进程中返回0,调用失败返回-1并设置errno
// 子进程的信号处理函数清除,代码和数据(堆、栈和静态数据)与父进程完全相同。
// 数据复制采用写时复制(copy on write),只有在任意进程(父进程或子进程)对数据执行了写操作时才会复制(先触发缺页中断,操作系统再给子进程分配内存并复制父进程数据),仍要尽量避免没必要的内存分配和数据复制。
// 文件描述符引用计数加一。
pid_t fork(void);

2. exec系列系统调用

  • 替换当前进程映像,失败返回-1,否则不返回
  • 原程序被新程序完全替换
  • 不会关闭原程序打开的文件描述符,除非该文件描述符被设置了类似SOCK_CLOEXEC的属性
    exec系列系统调用

3. 处理僵尸进程

  • 对于多进程程序,父进程一般要跟踪子进程的退出状态,因此子进程结束运行时,内核不会立即释放该进程的进程表表项,以满足父进程后续对该子进程退出信息的查询。
  • 子进程结束后,父进程读取其退出状态前,子进程处于僵尸态。
  • 另一种原因:父进程结束或异常终止,而子进程继续运行。此时子进程的PPID被操作系统设为1,即init进程,init进程接管子进程并等待它结束。父进程退出后,子进程退出前,子进程处于僵尸态。
  • 子进程结束时给父进程发送一个SIGCHLD信号,父进程可以捕获并调用waitpid函数彻底结束子进程。
#include<sys/types.h>
#include<sys/wait.h>
// 父进程中调用,等待子进程 结束并获取子进程的返回信息,避免僵尸进程产生。
pid_t wait(int* stat_loc);
pid_t wait(pid_t pid,int* stat_loc,int options);

子进程状态信息

4. 管道

管道

5. 信号量

  • 信号量原语
    • 临界区:程序对共享资源访问的代码,引发进程之间的竞态条件。
    • 信号量:一种特殊变量,只能取自然数值并且只支持两种操作:等待(wait)和信号(signal),通常称为P(传递,进入临界区)、V(释放,退出临界区)操作。
    • 假设有信号量SV
      • P(SV):如果SV值大于0,就将它减一;如果SV的值为0,则挂起进程的执行。
      • V(SV):如果有其它进程因为等待SV而挂起,则唤醒之;如果没有,则将SV加一。
        使用信号量保护关键代码段
#include <sys/sem.h>
// 创建一个新的信号量集,或者获取一个已存在的信号量集
// key: 标记一个全局唯一的信号量集
// num_sems: 要创建或者获取信号量集 中信号量的数目,如果是创建,必须指定该参数;如果是获取则可以设为0
// sem_flags: 指定一组标志,用于设置权限和其它标志
// 成功时返回一个正整数,是信号量集的标识符
int semget(key_t key, int num_sems, int sem_flags);
// 操作信号量
int semop(int sem_id,struct sembuf* sem_ops,size_t num_sem_ops);
// 直接控制信号量
int semctl(int sem_id, int sem_num, int command, ...);

6. 共享内存

#include<sys/shm.h>
// 创建或获取一段已存在的共享内存
int shmget(key_t key, size_t size, int shmflg);
// 把共享内存关联到进程的地址空间
void shmat(int shm_id,const void* shm_addr, int shmflg);
// 从进程地址空间中分离
int shmdt(const void* shm_addr);
// 控制共享内存的某些属性
int shmctl(int shm_id,int command,struct shmid_ds* buf);

#include<sys/mman.h>
#include<sys/stat.h>
#include<fcntl.h>
// 无关进程之间共享内存
int shm_open(const char* name, int oflag, mode_t mode);
// 标记为等待删除
int shm_unlink(const char* name);

7. 消息队列

#include<sys/msg.h>
// 创建或获取一个消息队列
int msgget(key_t key, int msgflg);
// 把一条消息添加到消息队列
int msgsnd(int msqid, const void* msg_ptr, size_t msg_sz, int msgflg);
// 从消息队列中获取消息
int msgrcv(int msqid, void* msg_ptr, size_t msg_sz, long int msgtype, int msgflg);
// 控制消息队列的某些属性
int msgctl(int msqid, int command, struct msqid_ds* buf);

8. IPC命令

ipcs命令

9. 在进程间传递文件描述符

  • 在新进程中创建新的文件描述符,指向内核中相同的文件表项。
  • 利用socket在进程间传递特殊的辅助数据。

第14章 多线程编程

1. Linux线程概述

  • 线程模型
    • 内核线程:运行在内核空间,由内核调度
    • 用户线程:运行在用户空间,由线程库调度
    • 线程的三种实现方式
      • 完全在用户空间实现:内核以进程为最小单位调度,创建和调度线程无需内核干预,速度快;多个线程无法运行在多CPU上;线程优先级只在进程内有效。
      • 完全由内核调度:线程创建、调度都交给内核,优缺点与完全在用户空间实现的方式相反。
      • 双层调度:混合两种模式,兼具前两种方式的优点。
  • Linux线程库

2. 创建线程和结束线程

#include<pthread.h>
// thread: 新线程的标识符
// attr: 线程属性,NULL为默认
// start_routine和arg分别指定新线程将运行的函数及其参数
int pthread_create(pthread_t* thread, const pthread_attr_t* attr,void* (*start_routine)(void*), void* arg);
// 线程结束后最好调用该函数以确保安全、干净地退出
void pthread_exit(void* retval);
// 回收其它线程,即等待其它线程结束
// thread: 目标线程标识符
int pthread_join(pthread_t thread, void** retval);
// 异常终止一个线程
int pthread_cancel(pthread_t thread);
// 设置线程能否被取消以及如何取消
int pthread_setcancelstate(int state,int *oldstate);
int pthread_setcanceltype(int type,int *oldtype);

3. 线程属性

4. POSIX信号量

5. 互斥锁

  • 互斥锁:保护关键代码段,以确保其独占式访问,类似于二进制信号量。

6. 条件变量

  • 条件变量:线程之间同步共享数据的值;提供了一种线程间的通知机制,当某个共享数据达到某个值的时候,唤醒等待这个共享数据的线程。

7. 线程同步机制包装类

8. 多线程环境

  • 可重入函数:内部使用了静态变量的函数不可重入。
  • 线程和进程:fork出的进程只保留调用fork的线程,子进程自动继承父进程的互斥锁和条件变量的状态,子进程可能不知道从父进程继承的互斥锁的具体状态,已锁住的互斥锁再次加锁会导致死锁。
  • 线程和信号:进程中的所有线程共享信号,每个信号可以单独设置信号掩码,但共享信号处理函数。因此应该定义一个专门的线程处理所有信号:先在主线程创建其它子线程之前设置好信号掩码,新的子线程就会继承这个信号掩码;然后在某个 线程中调用sigwait()函数等待信号并处理。调用了sigwait()函数就不应该再设置信号处理函数了。

第15章 进程池和线程池

1. 进程池和线程池概述

  • 主进程选择子进程为新任务服务的方式
    • 主动:随机算法;Round Robin算法(轮流选取)算法;用更智能的算法使任务在各个工作进程中更均匀地分配,减轻服务器整体压力。
    • 通过共享的工作队列同步。
      进程池模型

2. 处理多客户

多个子进程处理同一个客户连接上的不同任务

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值