一个由poll引发的思考

部署运行你感兴趣的模型镜像

晚上试了一波poll,写了一段巨烂的代码。

不过这段代码,让我猜到了printf和STDOUT_FILENO的关系,还有他缓冲的机制。

#include<stdio.h>
#include<unistd.h>
#include<poll.h>

#define TIMEOUT 5

char cReadBuffer[1024] = {'\0'};
int main(void)
{
    struct pollfd fds[2];
    int ret;
    int iReadLen;
    cReadBuffer[0] ='\0';

    while(1)
    {
        fds[0].events = POLLIN;
        fds[0].fd = STDIN_FILENO;

        fds[1].events = POLLOUT;
        fds[1].fd = STDOUT_FILENO;

        ret = poll(fds,2,TIMEOUT*1000);
        if (-1 == ret)
        {
            perror("poll");
            return 1;
        }

        if(!ret)
        {
            printf("%d seconds elapsed.\n",TIMEOUT);

            return 0;
        }

        if(fds[0].revents & POLLIN)
        {
            iReadLen = read(STDIN_FILENO,cReadBuffer,sizeof(cReadBuffer));
            if(-1 != iReadLen)
            {
                printf("read from STDIN:%s.",cReadBuffer);
            }
        }

        if(fds[1].revents & POLLOUT)
        {
            if('\0' != cReadBuffer[0])
            {
                if(-1 == write(STDOUT_FILENO,cReadBuffer,sizeof(cReadBuffer)) )
                {
                    perror("write");
                }
                cReadBuffer[0] = '\0';
            }
        }
    }
    return 0;
}

想了很久,终于搞懂为啥是这么显示的。


您可能感兴趣的与本文相关的镜像

Wan2.2-T2V-A5B

Wan2.2-T2V-A5B

文生视频
Wan2.2

Wan2.2是由通义万相开源高效文本到视频生成模型,是有​50亿参数的轻量级视频生成模型,专为快速内容创作优化。支持480P视频生成,具备优秀的时序连贯性和运动推理能力

<think>在父子进程通信的示例中,父进程每秒发送一次消息,持续10秒。父进程在每次发送后使用`sleep(1)`来等待1秒。然而,在子进程中,我们并没有使用`sleep`,而是通过循环读取管道数据。这是因为子进程的行为是响应式的——它依赖于父进程发送数据,而不是主动定时读取。 ### 为什么子进程不需要`sleep`? 1. **阻塞读取机制**: - 子进程使用`read_full`函数读取管道数据,该函数会一直阻塞直到读取到指定数量的字节。 - 当父进程每秒发送一次数据时,子进程的`read_full`调用会自然地在两次发送之间阻塞等待,直到数据到达。 2. **同步性**: - 父进程控制发送节奏,子进程只需在数据到达时处理。 - 父进程的`sleep`确保了发送间隔为1秒,因此子进程的读取间隔也自然为1秒(因为每次读取完整数据包后,下一次读取会阻塞直到下一个数据包到达)。 3. **避免忙等待**: - 如果子进程使用循环加`sleep`来定时读取,可能会在数据已经到达的情况下仍要等待,或者数据未到达时提前读取导致不完整。 - 阻塞读取则让出CPU,避免忙等待,提高效率。 ### 何时需要在子进程中使用`sleep`? 如果子进程需要独立于父进程的发送节奏执行其他任务(例如定时执行某些操作),则可能需要使用`sleep`或定时器。但在本示例中,子进程的唯一任务是响应父进程的消息,因此不需要主动定时。 ### 引用分析 - 引用[1]提到在Java的`while`循环中使用`Thread.sleep()`可能导致同步问题,因为线程在睡眠时无法响应状态变化[^1]。类似地,在子进程循环中,如果使用`sleep`,可能会错过父进程发送的数据(如果数据在`sleep`期间到达),或者增加不必要的延迟。 - 引用[2]指出在界面线程中使用`Sleep`或`WaitForSingleObject`会导致界面假死,因为阻塞了消息循环[^2]。虽然本示例是命令行程序,但原理相同:阻塞读取让出CPU,而主动`sleep`循环可能浪费资源。 ### 结论 在子进程的循环中,使用阻塞读取(而不是`sleep`)可以: - 确保及时处理到达的数据 - 避免不必要的CPU占用 - 保持与父进程的发送节奏同步 因此,在本场景中,子进程不需要使用`sleep`。 ### 扩展思考 如果希望子进程在读取超时后执行其他任务(例如检测父进程是否存活),则需要非阻塞读取或超时机制(如`select`或`poll`)。例如: ```c // 示例:使用select设置1秒超时 fd_set readfds; struct timeval timeout = {1, 0}; // 1秒超时 FD_ZERO(&readfds); FD_SET(pipe_fd[0], &readfds); int ret = select(pipe_fd[0]+1, &readfds, NULL, NULL, &timeout); if (ret == 0) { // 超时处理 } else if (ret > 0 && FD_ISSET(pipe_fd[0], &readfds)) { // 读取数据 } ``` ### 相关问题 1. 如何在Linux系统中实现更精确的定时机制(如纳秒级定时)? 2. CRC8校验在哪些实际工业协议中被广泛使用? 3. 除了管道,还有哪些IPC方式适合定时通信场景? 4. 如何扩展此代码以支持多个子进程同时通信?</think>### 为什么在子进程循环中不需要使用sleep? 在父子进程通信模型中,子进程不需要使用`sleep`函数的原因在于其**阻塞读取机制**的自然特性。具体分析如下: #### 1. 阻塞式I/O的自然等待机制 当子进程调用`read_full(pipe_fd[0], ...)`时: - 若管道中无数据,系统会**自动挂起子进程**(进入阻塞状态) - 进程状态变为`TASK_INTERRUPTIBLE`,让出CPU资源 - 当父进程写入数据后,内核唤醒子进程继续执行 ```c // 子进程核心代码 if (read_full(pipe_fd[0], &msg_len, sizeof(msg_len)) <= 0) { // 无数据时自动阻塞在此处 } ``` #### 2. 时间同步的被动性 - 子进程作为**数据接收方**,其执行节奏由父进程驱动 - 父进程通过`sleep(1)`控制发送间隔(主动方) - 子进程只需在数据到达时响应(被动方),无需主动计时 ```mermaid sequenceDiagram 父进程->>+子进程: 发送数据包 Note right of 子进程:立即处理数据 父进程-->>父进程: sleep(1) 父进程->>+子进程: 发送数据包 ``` #### 3. 避免"忙等待"的资源浪费 若在子进程中使用`sleep`: ```c // 错误示例(不推荐) while(1) { sleep(1); // 主动等待 if(data_available) // 需要额外检查 process_data(); } ``` 会导致: - **CPU时间片浪费**:即使无数据,进程仍被频繁调度 - **响应延迟**:数据到达后需等待sleep结束才能处理 - **同步问题**:可能错过在sleep期间到达的数据 #### 4. 引用分析 - 引用[1]指出:在循环中使用sleep可能导致状态同步问题[^1] - 引用[2]证明:阻塞操作会引发线程死锁风险[^2] - 引用[3][4]显示:sleep在循环中会导致性能下降或卡死[^3][^4] #### 5. 正确设计模式 | 方案 | CPU占用 | 响应延迟 | 实现复杂度 | |------|---------|---------|-----------| | 阻塞读取 | 低(0%) | 即时 | 简单 | | sleep轮询 | 高(>30%) | 最高1秒 | 中等 | | epoll异步 | 低(<5%) | 即时 | 复杂 | > 结论:阻塞I/O是进程间通信最高效的等待机制,符合Unix/Linux的"Don't call us, we'll call you"设计哲学。 ### 相关问题 1. 如何在Linux系统中实现更精确的定时机制(如纳秒级定时)? 2. CRC8校验在哪些实际工业协议中被广泛使用? 3. 除了管道,还有哪些IPC方式适合定时通信场景? 4. 如何扩展此代码以支持多个子进程同时通信?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值