首页 > 解决方案 > 使用 dup2() 写入文件后如何清理文件描述符?

问题描述

我想编写一个程序,将终端传递的参数写入两个名为(fichier,copie)的文件。

首先,两个文件中的参数顺序相同,以及在终端中为每个参数使用子进程提供的顺序。

其次,两个文件中的参数顺序相同,尽管它与终端中提供的参数顺序不同。

我已经使用“锁定”编写了下面的代码,以便在两个文件(fichier,副本)中写入每个参数,但似乎我无法在两个文件中写入参数。由于 dup2() 函数,我将所有参数写入第二个文件(副本)(我认为我的文件描述符有问题)。

如果有人可以向我解释如何清除文件描述符并将参数写入两个文件,我将非常高兴。

命令: ./try hello haha​​ hene

输出:在“副本”文件中,但“fichier”文件为空

  1. 88961 一个暴躁哈哈
  2. 88961 一个暴躁哈哈
  3. 88962 一个 ecrit hene
  4. 88962 一个 ecrit hene
  5. 88960 一个 ecrit 你好
  6. 88960 一个 ecrit 你好
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void fils(char *chaine){
    int fic1 = open("fichier", O_CREAT|O_APPEND|O_WRONLY,S_IRUSR|S_IWUSR);
    lseek(fic1 ,0 ,SEEK_SET);
    lockf(fic1 ,F_LOCK,0);
    dup2(fic1, 1);

    printf("%d a ecrit %s\n",getpid(),chaine);
    lseek(fic1 ,0 ,SEEK_SET);
    lockf(fic1 ,F_ULOCK,0);

    int fic2 = open("copie", O_CREAT|O_APPEND|O_WRONLY,S_IRUSR|S_IWUSR);
    lseek(fic2 ,0 ,SEEK_SET);
    lockf(fic2 ,F_LOCK,0);
    dup2(fic2, 1);
    printf("%d a ecrit %s\n",getpid(),chaine);

    int attente=rand()%2;
    fprintf(stderr,"%d attente de %d dans fichier et copie\n",getpid(),attente);
    sleep(attente);

    lseek(fic2 ,0 ,SEEK_SET);
    lockf(fic2 ,F_ULOCK,0);
    close(fic1);
    close(fic2);

    exit(EXIT_SUCCESS);
}

int main(int argc,char **argv){

    int i;
    pid_t pid;
    system("rm -f fichier copie");

    for(i=1;i<argc;i++){
        if((pid=fork())<0){
            printf("Erreur fork\n");
            exit(EXIT_FAILURE);
        }else if(pid==0){
            fils(argv[i]);
        }
    }
    exit(EXIT_SUCCESS);
}

标签: cprocesslockingforkipc

解决方案


没有写入任何内容,因为在您将标准输出切换为写入之前,您fichier不使用并且缓冲区未满。fflush(stdout)copie

这些lseek()电话大多毫无意义。写入将发生在文件末尾,因为O_APPEND. 它们背后的逻辑是确保整个文件被锁定,但是……</p>

lockf()电话毫无意义;该O_APPEND标志确保写入发生在文件末尾,并且单独进程中单独并发写入调用的内容不会为磁盘文件交错。

将这些与等待子进程死亡的循环结合在一起,会导致:

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

static void fils(char *chaine)
{
    int fic1 = open("fichier", O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR);
    dup2(fic1, 1);
    close(fic1);

    printf("%d a ecrit %s\n", (int)getpid(), chaine);
    fflush(stdout);

    int fic2 = open("copie", O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR);
    dup2(fic2, 1);
    close(fic2);
    printf("%d a ecrit %s\n", (int)getpid(), chaine);
    fflush(stdout);

    int attente = rand() % 2;
    fprintf(stderr, "%d attente de %d dans fichier et copie\n", (int)getpid(), attente);
    sleep(attente);

    exit(EXIT_SUCCESS);
}

int main(int argc, char **argv)
{
    int i;
    pid_t pid;

    remove("fichier");
    remove("copie");

    for (i = 1; i < argc; i++)
    {
        if ((pid = fork()) < 0)
        {
            fprintf(stderr, "Erreur fork\n");
            exit(EXIT_FAILURE);
        }
        else if (pid == 0)
        {
            fils(argv[i]);
        }
    }

    int corpse;
    int status;
    while ((corpse = wait(&status)) > 0)
    {
        printf("%d: child %d exited with status 0x%.4X\n",
               (int)getpid(), corpse, status);
    }
    return(EXIT_SUCCESS);
}

当我运行它时,我得到了输出:

$ open29 hello haha hene
95396 attente de 1 dans fichier et copie
95395 attente de 1 dans fichier et copie
95397 attente de 1 dans fichier et copie
95394: child 95397 exited with status 0x0000
95394: child 95396 exited with status 0x0000
95394: child 95395 exited with status 0x0000
$ cat fichier
95395 a ecrit hello
95396 a ecrit haha
95397 a ecrit hene
$ cat copie
95396 a ecrit haha
95395 a ecrit hello
95397 a ecrit hene
$

请注意,孩子们都睡了相同的时间。在播种时srand()要注意在不同的孩子中有不同的序列(例如,srand(getpid())在每个孩子的顶部调用fils())。

我也确实运行了您的代码版本,保留了您的锁定方案,但fflush(stdout)在调用printf(). 输出并没有本质上的不同。该文件fichier包含带有hello, hene, haha;的行 该文件copie包含带有hello, haha,的行hene。关键的变化是使用fflush(stdout);来获取写入的数据fichier以及copie.


推荐阅读