一次重定向引起的异步IO

在使用 dup/dup2 进行IO重定向时,因缓冲区问题触发异步IO,导致输出异常。代码中,printf函数导致683行数据写入文件不完整,部分数据输出到终端。查阅资料得知,标准IO在重定向到文件后变为全缓冲,当缓冲区未满时进程结束,未刷新的数据被打印到终端。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在用dup/dup2做IO重定向的时候,由于缓冲区的问题出现了一次异步IO,导致无法正常输出正确的结果。
先贴出代码:

/* 
 * 从文件里面读出1000个随机数,进行排序,再写到另一个文件中(使用dup/dup2)
 *  
 */

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef char STR[32];

void quick(int *a, int i, int j);

int main(void)
{
    int fd, fd2;
    int save_fd, save_fd2;
    int i;

    if ((fd = open("data.txt", O_RDONLY)) < 0) {
        perror("open data.txt");
        exit(1);
    }

    if ((fd2 = open("sort_w.txt", O_RDWR|O_CREAT, 0644)) < 0) {
        perror("open sort_w.txt");
        exit(1);
    }

    save_fd = dup(STDIN_FILENO);
    save_fd2 = dup(STDOUT_FILENO);

    dup2(fd, STDIN_FILENO);
    dup2(fd2, STDOUT_FILENO);
 close(fd);
    close(fd2);

    STR *st = malloc(sizeof(STR) * 1000);
    memset(st, 0, sizeof(STR)*1000);

    int buf[1000] = {0};

    for (i = 0; i < 1000; i++)
        scanf("%s", st[i]);

    for (i = 0; i < 1000; i++)
        buf[i] = atoi(st[i]);

    quick(buf, 0, 999);

    char tmp[128] ={0};
    for (i = 0; i < 1000; i++) {
        memset(tmp, 0, 128);
        sprintf(tmp, "%d\n", buf[i]);

        /* error */
    //  printf("%s", tmp);             // apue 标准输出关联到一个文件的时候,变成全缓冲的。
        write(STDOUT_FILENO, tmp, strlen(tmp));
    }

    dup2(save_fd, STDIN_FILENO);
    dup2(save_fd2, STDOUT_FILENO);
    close(save_fd);
    close(save_fd2);

    free(st);
    return 0;
}


void quick(int *a, int i, int j)
{
    int m, n, temp;
    int k;
    m = i;
    n = j;
    k = a[(i + j) / 2]; /*选取的参照*/
    do {
        while (a[m]>k&&m<j) m++; /* 从左到右找比k大的元素*/
        while (a[n]<k&&n>i) n--; /* 从右到左找比k小的元素*/
        if (m <= n) { /*若找到且满足条件,则交换*/
            temp = a[m];
            a[m] = a[n];
            a[n] = temp;
            m++;
            n--;
        }
    } while (m <= n);
    if (m<j) quick(a, m, j); /*运用递归*/
    if (n>i) quick(a, i, n);
}

问题出在注释的printf那一行,用write一切正常运行,用printf的时候出现如下结果。

forker@L:homework$ ./a.out 
5
30094
29970
29882
29858
29769
29733
29690
29679
29673
29573
29434
29353
29309
29308
29269
29257
28751
28420
...
173

再来看看排序后生成的文件中:

673 30641
674 30637
675 30629
676 30628
677 30451
678 30401
679 30373
680 30364
681 30320
682 30199
683 3013

对比可以看出来,用printf在文件中写入了683行,并且没有写完,应该是30135,之后的数据打印到终端上。
后来,查阅资料Apue中说:
标准IO在关联到终端的时候是行缓冲的,在重将标准IO重定向到一个文件之后,这个时候就变成了全缓冲的。可以看到在第一次缓冲区满了的时候,IO例程进行刷新缓冲区,于是写入了文件。之后再将剩下的数据写到缓冲区,这个时候缓冲区并没有满,也就没有立刻刷新。接下来,标准IO又关联到终端,在进程终止之前,开始刷新缓冲区,于是剩下的数据被打印到终端上。
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值