UNIX管道是否必须由两个不同进程访问?——针对lmbench上下文切换测量场景的技术问询
回答:UNIX管道的访问主体与lmbench测试场景的设计
Great question! Let's break this down into two key parts: the general behavior of UNIX pipes, and why lmbench uses two processes for context switch measurement.
核心结论:UNIX管道并非必须由不同进程访问
UNIX管道的设计并没有强制要求必须由多个进程访问——单个进程完全可以创建并使用同一个管道的读写两端。比如,一个进程可以先调用pipe()创建管道,然后自己向写端写入数据,再从读端读取数据,这是完全合法的操作,内核会正确处理管道内的数据流转。
这种单进程使用管道的场景虽然少见,但在某些特殊需求下会用到,比如实现简单的自缓冲数据处理,或者利用管道的原子性特性做一些内部同步。
为什么lmbench(以及你的测试代码)要用两个进程访问管道?
这完全是由测量上下文切换成本的测试目标决定的:
- 上下文切换是内核在多个就绪进程之间切换CPU执行权的操作,只有当一个进程进入阻塞状态(比如等待I/O完成),且存在其他就绪进程时,内核才会触发上下文切换。
- 如果用单个进程访问自己的管道,读写操作不会导致进程阻塞:写端写入的数据会直接进入内核管道缓冲区,读端可以立即读取,进程全程处于运行状态,不会触发内核调度,自然无法测量到上下文切换的耗时。
结合你提供的代码来看,这个测试的设计逻辑非常清晰:
- 用
fork()创建父子两个进程,通过sched_setaffinity()把它们绑定到同一个CPU核心,避免跨CPU调度带来的额外开销干扰测量结果。 - 创建两个管道,让父子进程形成一个"唤醒循环":
- 父进程向第一个管道写空数据后,尝试从第二个管道读取数据——此时第二个管道没有数据,父进程进入阻塞状态,内核调度子进程运行。
- 子进程从第一个管道读取空数据后,向第二个管道写空数据,再尝试从第一个管道读取——此时第一个管道没有新数据,子进程进入阻塞状态,内核切回父进程。
- 循环执行n次这个流程,用总耗时除以n,就能得到单次上下文切换的平均成本。
额外补充:单进程使用管道的简单示例
如果要验证单进程也能使用管道,可以运行这段极简代码:
#include <stdio.h> #include <unistd.h> #include <string.h> int main() { int pipefd[2]; char buf[100]; if (pipe(pipefd) == -1) { perror("pipe"); return 1; } // 单进程写管道 const char* msg = "Hello from single process!"; write(pipefd[1], msg, strlen(msg)+1); // 单进程读管道 read(pipefd[0], buf, sizeof(buf)); printf("Read from pipe: %s\n", buf); close(pipefd[0]); close(pipefd[1]); return 0; }
这段代码会正常输出写入的字符串,证明单进程完全可以访问自己创建的管道。
内容的提问来源于stack exchange,提问作者Jia
相关产品推荐
相关产品推荐

