mirror of
https://github.com/Estom/notes.git
synced 2026-02-03 02:23:31 +08:00
IO与通信彻底解决
This commit is contained in:
0
Linux/Linxu系统编程/IO编程.md
Normal file
0
Linux/Linxu系统编程/IO编程.md
Normal file
0
Linux/Linxu系统编程/并行编程.md
Normal file
0
Linux/Linxu系统编程/并行编程.md
Normal file
0
Linux/Linxu系统编程/网络编程.md
Normal file
0
Linux/Linxu系统编程/网络编程.md
Normal file
@@ -6,6 +6,7 @@
|
||||
- 论文复现(一周时间)
|
||||
|
||||
### 工作
|
||||
> [C++学习路线](https://www.zhihu.com/collection/589776737)
|
||||
|
||||
- 制作简历(明天)√
|
||||
- 知识复习——语言
|
||||
@@ -13,9 +14,9 @@
|
||||
- [x] 基础语法 √
|
||||
- [x] 标准库 STL√
|
||||
- [x] 面向对象 √
|
||||
- [ ] 设计模式(有道云笔记,gitee 设计模式库,书)
|
||||
- [ ] 设计模式(有道云笔记,源网址,gitee设计模式库,书)
|
||||
- [ ] effective 系列
|
||||
- [ ] 系列视频
|
||||
- [ ] 系列视频(知乎上收藏的内容)
|
||||
- [ ] 问题专项解决
|
||||
- Java(两周)
|
||||
- [ ] 语法
|
||||
@@ -50,10 +51,14 @@
|
||||
- [x] 文件管理
|
||||
- [x] 系统调用
|
||||
- 编程实战
|
||||
- [ ] 网络编程(socket网络编程)
|
||||
- [ ] 并行编程(多线程并发编程)
|
||||
- [ ] 系统编程(linux操作系统编程)
|
||||
|
||||
- linux系统编程
|
||||
- [ ] 网络编程(socket网络编程)
|
||||
- [ ] 并行编程(多线程、多进程并发编程)
|
||||
- [ ] IO编程(实现多种机制的IO方式select/poll/epoll/signal/async等)
|
||||
- [ ] 系统编程(linux操作系统编程)
|
||||
- C++通用库跨平台编程
|
||||
- [ ] 网络编程(socket跨平台网络编程)
|
||||
- [ ] 并行编程(多线程、多进程并发编程)
|
||||
- 刷题
|
||||
- 力扣(学习、题库、讨论。侧重于刷算法类型的题目和相关讨论)
|
||||
- 学习:3-5 本书的学习需要阅读的书籍如下
|
||||
|
||||
@@ -5,4 +5,31 @@
|
||||
|
||||
|
||||
## 收获
|
||||
* 对网络编程和并行编程的内容进行了复习。
|
||||
* 通信原理:Linux的五种IO模型。阻塞IO、非阻塞IO、IO复用、信号、异步IO。前四种是同步,最后是异步,第二阶段从内核到用户复制数据是否阻塞。1、3是阻塞、2、4是非阻塞,第一阶段是否进行阻塞。
|
||||
* Linux网络编程:Linux socket编程。主要通过bind、accept、socket、listen、read、send实现
|
||||
* Linux并行编程:同步:pthread/各种lock。通信:pipe/FIFO
|
||||
* Linux IO编程:file、epoll
|
||||
* C++网络编程:boost-asio
|
||||
* C++并行编程:C++多线程机制。C++线程同步机制:Future/Async、thread/promise、mutex/guard_lock/unique_lock/condition_variable信号量(互斥锁)与条件变量
|
||||
|
||||
* Linux系统编程还其本身大量的网络编程和并行编程实现方案。
|
||||
* C++的标准库和其他库也封装了网络编程和并行编程方案。
|
||||
* 网络编程和并行编程本质上是一种东西。并行编程是实现多线程、线程同步、线程通信。网络编程是实现两个远程线程的同步和通信。
|
||||
|
||||
|
||||
* 对几个概念的理解
|
||||
* 网络编程
|
||||
* 网络多进程、多线程。进程/线程的同步和通信。socket实现。是并发编程的一种形式。
|
||||
* 并发编程
|
||||
* 本地多进程、多线程。包含进程/线程同步、进程/线程通信。
|
||||
* 进程同步
|
||||
* 属于并发编程的一个环节
|
||||
* 进程通信
|
||||
* 属于并发编程的一个环节
|
||||
* IO
|
||||
* 本地设备IO机制。同步、异步、阻塞、非阻塞、IO复用等。
|
||||
* 几个方案用来实现以上哪些内容。
|
||||
* socket 实现网络编程。
|
||||
* 信号量、管道、信号、消息队列:进程同步与进程通信
|
||||
* select/poll/epoll IO方式
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
# 2.4 进程通信
|
||||
> 参考文献
|
||||
> * [https://blog.csdn.net/qq_40989769/article/details/110481553](https://blog.csdn.net/qq_40989769/article/details/110481553)
|
||||
|
||||
> linux实现多线程多进程的方法有很多。可以在linux系统编程部分好好了解。在这里只引入Linux实现几种进程通信的方式。
|
||||
|
||||
## 0 进程通信的定义
|
||||
|
||||
@@ -38,24 +42,34 @@
|
||||
4. **无名管道通信**。无名管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
|
||||
5. **高级管道通**信。高级管道(popen):将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们成为高级管道方式。
|
||||
6. **有名管道通信**。有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
|
||||
7. 消息队列通信。消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
|
||||
7. **消息队列通信**。消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
|
||||
8. **套接字通信**。套接字( socket ) : 套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。
|
||||
|
||||
## 1 信号量通信
|
||||
> 参考文献
|
||||
> * [https://blog.csdn.net/csdn_kou/article/details/81240666](https://blog.csdn.net/csdn_kou/article/details/81240666)
|
||||
### 函数接口
|
||||
* 进程中的信号量函数
|
||||
```
|
||||
```
|
||||
* 线程中的信号量函数。
|
||||
* linux进程中的信号量函数
|
||||
```C++
|
||||
// linux操作系统
|
||||
```
|
||||
* linux线程中的信号量函数。
|
||||
```C++
|
||||
// linux操作系统
|
||||
pthread_mutex_t
|
||||
pthread_mutex_init
|
||||
pthread_mutex_lock
|
||||
pthread_mutex_unlock
|
||||
pthread_mutex_destroy
|
||||
```
|
||||
* 跨平台C库中的信号量(window/linux都可以使用)
|
||||
```C++
|
||||
// 标准库中的进程同步和通信
|
||||
mutex/recursive_mutex;
|
||||
guard_lock;
|
||||
unique_lock;
|
||||
condition_variable;
|
||||
```
|
||||
### 编程实现
|
||||
```C
|
||||
#include <time.h>
|
||||
@@ -165,6 +179,11 @@ int main(int argc, char *argv[])
|
||||
|
||||
## 2 信号通信
|
||||
|
||||
### 函数接口
|
||||
* linux下的信号机制
|
||||
```
|
||||
```
|
||||
|
||||
### 编程实现
|
||||
```C
|
||||
```
|
||||
@@ -617,7 +636,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
```
|
||||
|
||||
## 9 进程通信的同步方式
|
||||
## 9 进程通信的同步与阻塞
|
||||
|
||||
### 同步异步、阻塞非阻塞
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# 五种IO模型
|
||||
|
||||
> linux实现IO过程的方法有很多。这里只对五种模型进行介绍。如果要实现五种IO过程,在linux系统编程部分进行学习。
|
||||
|
||||
|
||||
## 1 I/O 模型
|
||||
|
||||
* 一个输入操作通常包括两个阶段:
|
||||
@@ -77,9 +80,11 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
||||
|
||||
* 同步IO的主要区别在第一个阶段。阻塞式IO、IO复用第一阶段会阻塞。非阻塞式IO、信号驱动IO在第一阶段不会阻塞。
|
||||

|
||||
## 2 I/O 复用
|
||||
|
||||
* select/poll/epoll 都是 I/O 多路复用的具体实现,select 出现的最早,之后是 poll,再是 epoll。
|
||||
|
||||
## 2 I/O 复用实现方式
|
||||
|
||||
> select/poll/epoll 都是 I/O 多路复用的具体实现,select 出现的最早,之后是 poll,再是 epoll。
|
||||
|
||||
### select
|
||||
|
||||
@@ -274,9 +279,9 @@ else
|
||||
|
||||
### 应用场景
|
||||
|
||||
* 很容易产生一种错觉认为只要用 epoll 就可以了,select 和 poll 都已经过时了,其实它们都有各自的使用场景。
|
||||
1. select 应用场景。select 的 timeout 参数精度为微秒,而 poll 和 epoll 为毫秒,因此 select 更加适用于实时性要求比较高的场景,比如核反应堆的控制。select 可移植性更好,几乎被所有主流平台所支持。
|
||||
很容易产生一种错觉认为只要用 epoll 就可以了,select 和 poll 都已经过时了,其实它们都有各自的使用场景。
|
||||
1. select 应用场景。select 的 timeout 参数精度为微秒,而 poll 和 epoll 为毫秒,因此 select 更加适用于实时性要求比较高的场景,比如核反应堆的控制。select 可移植性更好,几乎被所有主流平台所支持。
|
||||
|
||||
2. poll 应用场景。poll 没有最大描述符数量的限制,如果平台支持并且对实时性要求不高,应该使用 poll 而不是 select。
|
||||
|
||||
3. epoll 应用场景。只需要运行在 Linux 平台上,有大量的描述符需要同时轮询,并且这些连接最好是长连接。需要同时监控小于 1000 个描述符,就没有必要使用 epoll,因为这个应用场景下并不能体现 epoll 的优势。需要监控的描述符状态变化多,而且都是非常短暂的,也没有必要使用 epoll。因为 epoll 中的所有描述符都存储在内核中,造成每次需要对描述符的状态改变都需要通过 epoll_ctl() 进行系统调用,频繁系统调用降低效率。并且 epoll 的描述符存储在内核,不容易调试。
|
||||
2. poll 应用场景。poll 没有最大描述符数量的限制,如果平台支持并且对实时性要求不高,应该使用 poll 而不是 select。
|
||||
|
||||
3. epoll 应用场景。只需要运行在 Linux 平台上,有大量的描述符需要同时轮询,并且这些连接最好是长连接。需要同时监控小于 1000 个描述符,就没有必要使用 epoll,因为这个应用场景下并不能体现 epoll 的优势。需要监控的描述符状态变化多,而且都是非常短暂的,也没有必要使用 epoll。因为 epoll 中的所有描述符都存储在内核中,造成每次需要对描述符的状态改变都需要通过 epoll_ctl() 进行系统调用,频繁系统调用降低效率。并且 epoll 的描述符存储在内核,不容易调试。
|
||||
@@ -4,26 +4,11 @@
|
||||
> * [https://www.zhihu.com/question/19732473/answer/14413599](https://www.zhihu.com/question/19732473/answer/14413599)
|
||||
> * [https://www.cnblogs.com/shiysin/articles/10689761.html](https://www.cnblogs.com/shiysin/articles/10689761.html)
|
||||
> * [https://blog.csdn.net/jolin678/article/details/49611587](https://blog.csdn.net/jolin678/article/details/49611587)
|
||||
|
||||
## 1 同步异步、阻塞非阻塞
|
||||
> * [https://blog.csdn.net/qq_40989769/article/details/110481553](https://blog.csdn.net/qq_40989769/article/details/110481553)
|
||||
|
||||
|
||||
### nodejs中相关定义
|
||||
|
||||
* **同步式I/O(Synchronous I/O)或阻塞式I /O (Blocking I/O)**。线程/进程在执行中如果遇到磁盘读写或网络通信(统称为I/O 操作),通常要耗费较长的时间,这时 操作系统会剥夺这个线程/进程的CPU 控制权,使其暂停执行,同时将资源让给其他的工作线程,这种线程调度方式称为阻塞 。当I/O 操作完毕时,操作系统将 这个线程的阻塞状态解除,恢复其对CPU的控制权,令其继续执行。
|
||||
* **异步式 I/O (Asynchronous I/O)或非阻塞式I/O (Non-blocking I/O)**。则针对所有I/O 操作不采用阻塞的策略。当线程 遇到I/O 操作时,不会以阻塞的方式等待I/O 操作的完成或数据的返回,而只是将I/O 请求发送给操作系统,继续执行下一条语句。当操作系统完成I /O 操作时,以事件的形式通知执行I/O 操作的线程,线程会在特定时候处理这个事件。为了处理异步I/O,线程必须有事件循环,不断地检查有没有未处 理的事件,依次予以处理。
|
||||
* **并发方式**。阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过**多线程**。而非阻塞模式下,一个线程永远在执行计算操作,这个线程所使用的CPU 核心利用率永远是100%,**I/O 以事件的方式通知**。在阻塞模式下,多线程往往能提高系统吞吐量,因为一个线程阻塞时还有其他线程在工作,多线程可以让CPU 资源不被阻塞中的线程浪费。而在非阻塞模式下,线程不会被I/O 阻塞,永远在利用CPU。多线程带来的好处仅仅是在多核CPU 的情况下利用更多的核,而Node.js的单线程也能带来同样的好处。这就是为什么Node.js 使用了单线程、非阻塞的**事件编程模式**。
|
||||
|
||||
|
||||
### 一种更深的理解——在看完五种IO模型之后的反思
|
||||
|
||||
* 同步和异步是针对**应用程序和内核**的交互而言的;
|
||||
* 同步指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪。
|
||||
* 异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知。
|
||||
* 阻塞和非阻塞是针对于**进程在访问数据**的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作函数的实现方式;
|
||||
* 阻塞方式下读取或者写入函数将一直等待,
|
||||
* 非阻塞方式下,读取或者写入函数会立即返回一个状态值。
|
||||
|
||||
## 1 进程通信的方式——同步异步、阻塞非阻塞
|
||||
|
||||
### 同步异步
|
||||
|
||||
@@ -38,8 +23,31 @@
|
||||
* 阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
|
||||
* 非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
|
||||
|
||||
## 2 设备IO的方式——同步异步、阻塞非阻塞
|
||||
### nodejs中相关定义
|
||||
|
||||
## 3 实现方式
|
||||
* **同步式I/O(Synchronous I/O)或阻塞式I /O (Blocking I/O)**。线程/进程在执行中如果遇到磁盘读写或网络通信(统称为I/O 操作),通常要耗费较长的时间,这时 操作系统会剥夺这个线程/进程的CPU 控制权,使其暂停执行,同时将资源让给其他的工作线程,这种线程调度方式称为阻塞 。当I/O 操作完毕时,操作系统将 这个线程的阻塞状态解除,恢复其对CPU的控制权,令其继续执行。
|
||||
* **异步式 I/O (Asynchronous I/O)或非阻塞式I/O (Non-blocking I/O)**。则针对所有I/O 操作不采用阻塞的策略。当线程 遇到I/O 操作时,不会以阻塞的方式等待I/O 操作的完成或数据的返回,而只是将I/O 请求发送给操作系统,继续执行下一条语句。当操作系统完成I /O 操作时,以事件的形式通知执行I/O 操作的线程,线程会在特定时候处理这个事件。为了处理异步I/O,线程必须有事件循环,不断地检查有没有未处 理的事件,依次予以处理。
|
||||
* **并发方式**。阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过**多线程**。而非阻塞模式下,一个线程永远在执行计算操作,这个线程所使用的CPU 核心利用率永远是100%,**I/O 以事件的方式通知**。在阻塞模式下,多线程往往能提高系统吞吐量,因为一个线程阻塞时还有其他线程在工作,多线程可以让CPU 资源不被阻塞中的线程浪费。而在非阻塞模式下,线程不会被I/O 阻塞,永远在利用CPU。多线程带来的好处仅仅是在多核CPU 的情况下利用更多的核,而Node.js的单线程也能带来同样的好处。这就是为什么Node.js 使用了单线程、非阻塞的**事件编程模式**。
|
||||
|
||||
### 一种更深的理解——在看完五种IO模型之后的反思
|
||||
|
||||
* 同步和异步是针对**应用程序和内核**的交互而言的;
|
||||
* 同步指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪。可以是阻塞等待也可以是非阻塞的轮询。
|
||||
* 异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知。
|
||||
* 阻塞和非阻塞是针对于**进程在访问数据**的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作函数的实现方式;
|
||||
* 阻塞方式下读取或者写入函数将一直等待,
|
||||
* 非阻塞方式下,读取或者写入函数会立即返回一个状态值。
|
||||
|
||||
## 3 进程通信和设备IO的关系
|
||||
|
||||
1. 关于同步异步、阻塞非阻塞。交互方式,分别有两种应用。一种用在**进程间的同步和通信**上;一种用在**设备IO过程**中。必须要进行区分。
|
||||
|
||||
2. 当然两者似乎也有重合的部分。例如在socket编程(网络编程)网络进程通信过程中,即是一种**网络进程通信(两个远程进程)**,也是一种**网络IO过程(一个进程与网卡设备IO)**。可以看成两个远程的网络进程通信,也可以看成单个线程与本地网卡设备的IO过程。
|
||||
|
||||
3. 所以在某种程度上。可以把两个进程的通信,看成某一个用户进程的IO过程,而另一个进程看成是设备。
|
||||
|
||||
## 4 实现方式
|
||||
### 同步阻塞通信
|
||||
> 在此种方式下,用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行。
|
||||
|
||||
@@ -50,7 +58,7 @@
|
||||
### 同步非阻塞
|
||||
> 在此种方式下,用户进程发起一个IO操作以后边可返回做其它事情,但是用户进程需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费。其中目前JAVA的NIO就属于同步非阻塞IO。
|
||||
|
||||
* poll机制。轮训IO信号,虽然没有阻塞,但是在循环中一致确认IO是否完成。效率很低。
|
||||
* poll机制。轮训IO信号,虽然没有阻塞,但是在循环中一直确认IO是否完成。效率很低。
|
||||
|
||||
|
||||
### 异步非阻塞通信
|
||||
|
||||
Reference in New Issue
Block a user