p716~p757, 分两次, 716~733, 733~757.
摘要
这一章要讲到网络编程中著名的select模式, epoll模式等.
概述
应用级并发的作用
- 访问慢速I/O设备. 当应用等待慢速I/O设备将数据写入内存时, 可以将CPU交出去执行其他任务, 保持CPU的使用率.
- 与人交互. 例如人可以一边听歌, 一边打游戏, 还可以收QQ消息~
- 通过推迟工作以降低延迟.
- 服务多个网络客户端
- 在多核机器上进行并行计算
3种并发
- 进程并发
- I/O多路复用
- 线程并发
进程并发
使用fork, exec, waitpid的方法, 在父进程接收客户端连接请求, 然后创建新的子进程来这个客户端提供服务.(比如理发店里, 前台接待客户, 然后将新客户分配一个空闲的理发师.)
优点: 隔离清晰, 互相之间不会影响.
缺点: 共享信息和通信比较麻烦. 比较费资源, 单机达不到很高的并发量
I/O多路复用
核心是select函数, 将所有的描述符放在一个集合fd_set
中, 调用select函数, 去内核执行一次查询操作, 查询的结果放在fd_set
中, 再逐个去检查这些描述符的状态, 如果打开(状态为1)的话, 就执行读取操作.
#include <sys/select.h>
int select(int n, fd_set *fdset, NULL, NULL, NULL);
FD_ZERO(fd_set *fdset); //置空fdset
FD_CLR(int fd, fd_set *fdset); //置空fd所在的位
FD_SET(int fd, fd_set *fdset); //设置fd所在位为1
FD_ISSET(int fd, fd_set *fdset); //检查fd所在位是否为1
更多关于I/O复用的, 可以参考这个博客, 阻塞I/O、非阻塞I/O和I/O多路复用
线程并发
每个线程有自己的线程上下文(thread context), 包括一个唯一的整数线程ID(Thread ID), 栈, 栈指针, 程序计数器, 通用目的寄存器和条件码. 所有运行在一个进程内的线程共享该进程的整个虚拟地址空间.
多线程与多进程类似, 有以下几个不同点
- 线程上下文更小, 切换更轻量级
- 第一个运行的线程为主线程, 所有线程间是对等的, 一个线程可以杀死任何对等线程, 或者等待对等线程终止.
- 线程间容易共享数据