如何使用不同的进程读取文件?

问题描述

我想使用不同的进程读取文件,但是当我尝试第一个创建的子进程读取所有文件时,其他进程无法读取该文件。例如,我使用 101,102 和 103 个进程 ID 创建了 3 个不同的进程。

从 = 101 读取。
b 从 = 101 读取。
c 从 = 101 读取。
d 从 = 101 读取。

但我想那样阅读

从 = 101 读取。
b 从 = 103 读取。
c 从 = 102 读取。
d 从 = 103 读取。

我尝试使用信号量和互斥锁来解决它,但我做不到。请帮帮我好吗?

int i=0,pid;
char buffer[100];

for(i=0; i<3; i++){
    pid = fork();
    if(pid == 0){
        sem_wait(&mutex); // sem_t mutex is global.           
        while(read(fd,&buffer[j],1) == 1){
            printf("%c read from = %d\n",buffer[j],getpid());
            j++;
        }
        sem_post(&mutex);
        exit(0);
    }
    else{
        wait(NULL);
    }
}

解决方法

问题在于,即使每个进程都有自己的文件描述符,但那些文件描述符都共享同一个打开的文件描述('descriptor' != 'description'),读取位置存储在文件描述中,而不是文件描述符。因此,当任何子进程读取文件时,它会移动所有子进程的文件指针。

有关这方面的更多信息,请参阅以下 POSIX 规范:

没有互斥锁或其他类似的小工具可以为您解决这个问题——至少,不能靠它自己。最简单的解决方法是在子进程中重新打开文件,以便每个子进程都有一个单独的打开文件描述以及它自己的文件描述符。或者,每个孩子都必须使用互斥锁,倒带文件,读取数据,并在完成后释放互斥锁。在子进程中(重新)打开文件更简单。

请注意,互斥量必须在进程之间共享才能相关。请参阅 pthread_mutexattr_setpshared() 的 POSIX 规范。这不是使用默认互斥体属性值设置的。

,

您有两个问题阻止了您想要的内容,并且会导致(仅)第一个孩子读取整个文件

  • 父进程在创建每个子进程后立即等待它,然后再派生更多子进程。因此,在创建第一个孩子之后,它将等待该孩子退出循环并创建第二个孩子。要解决这个问题,您需要有两个循环父级——第一个只创建子级,第二个等待它们:

      for (...) {
          if (fork() == 0) {
              // run the child
              exit(0); } }
      for (...)
          wait(NULL);  // wait for a child
    
  • 您的阅读循环在内部 sem_wait/sem_post。所以第一个孩子将获得互斥锁,然后在释放互斥锁之前继续读取整个文件。在文件被完全读取之前,后续子进程不会获得互斥锁,因此他们会看到他们处于 EOF 并退出。要解决此问题,您需要在 while 循环内移动 sem_wait/sem_post 调用:

      while (!done) {
          sem_wait(&mutex);
          if (read(...) == 1) { ...
          } else {
              done = true; }
          sem_post(&mutex); }
    

您甚至可能根本不需要信号量——内核将同步不同进程之间的读取,因此每个字节都将由一个孩子读取。这将允许子进程并行处理(处理字节),而不是一次只允许一个子进程运行。

当然,即使有上述情况,一个孩子可能会在另一个孩子开始运行并处理它们之前处理很多字节,所以如果处理速度快并且字节很少,它们可能仍然被第一个孩子消耗掉。