【问题标题】:How can I clean a file descriptor after writing into a file with dup2()?使用 dup2() 写入文件后如何清理文件描述符?
【发布时间】:2020-04-20 02:13:29
【问题描述】:

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

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

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

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

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

命令: ./try hello haha​​ hene

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

  1. 88961 一个 ecrit 哈哈
  2. 88961 一个 ecrit 哈哈
  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);
}

【问题讨论】:

  • 我很难理解你在问什么,但我认为你完全误解了 dup2 函数的作用。它似乎对您的问题一点用处都没有。
  • 我也不明白你认为lockf在这里做了什么。

标签: c process locking fork ipc


【解决方案1】:

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

lseek() 的调用大多毫无意义;由于O_APPEND,写入将发生在文件末尾。它们背后的逻辑是确保整个文件被锁定,但是……

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() 的顶部)。

我还运行了您的代码版本,保留了您的锁定方案,但在调用 printf() 之后使用了 fflush(stdout)。输出并没有本质上的不同。文件fichier 包含带有hellohenehaha 的行;文件copie 包含带有hellohahahene 的行。关键变化是使用fflush(stdout); 来获取写入fichiercopie 的数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-20
    • 1970-01-01
    • 1970-01-01
    • 2020-04-26
    • 2019-06-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多