我有一个文件instructions.txt
(由文件指针fp
表示),由12行组成(每行包含字节ls\n
和ps\n
)。
最初,主进程以读取模式打开文件,创建并初始化共享内存区域mem
,并使用fork()
创建另外11个进程。
12个进程中的每一个都应该从文件中读取一行并执行该指令。在进入最外面的while
块之前,在所有进程中调用ftell(fp)
将返回0.
问题是,在进入最外层if
块的第一个进程使用fgets
读取一行后,在其他进程中调用ftell
将返回36(文件大小为12x3 = 36字节)。首先执行ftell
的过程中的fgets
仍会返回3(第一行的结尾)。
因此,下次任何流程调用fgets
时,都会返回EOF
共享内存区mem
用作"数组"其中第1到第12个元素包含12个进程的PID,第0个元素用作索引来决定哪个进程将进入最外面的if
块。
以下是导致此问题的代码段 -
while(mem[0] > 0)
{
printf("(%u) pos = %ld\n", curr_pid, ftell(fp));
// only the process whose PID matches the value in
// mem[mem[0]] can enter
if(curr_pid == mem[mem[0]])
{
printf("\n\nprocess %u enters CS\n", curr_pid);
char instr[100];
printf("pos before read = %ld\n", ftell(fp));
if(fgets(instr, 100, fp) == NULL)
{
perror("fgets error or EOF");
//return 1;
}
printf("pos after read = %ld\n", ftell(fp));
instr[strlen(instr)-1] = 0;
printf("process %u executing command: %s, size = %lu\n", curr_pid, instr, strlen(instr));
/* execute instruction */
char *args[] = {instr, NULL};
pid_t exec_pid = fork();
if(exec_pid == -1)
{
perror("fork error");
}
else if(exec_pid == 0) // child execs
{
execvp(instr, args);
perror("execvp error");
return 1;
}
printf("process %u leaving CS\n", curr_pid);
sleep(5);
mem[0]--; // alow next process to enter and read
}
sleep(1);
}
下面
(FILE *) fp
是指向instructions.txt
文件的文件指针
(int *) mem
是附加到所有12个进程的共享内存
mem[0]
是在if
中找到要选择进入mem
块的进程的PID(即1到12之间的值)(即, mem[mem[0]]
包含mem[0]
进程的PID
(pid_t) curr_pid
为每个流程存储自己的PID
实质上,只有一个进程进入最外面的if
块,而其他进程则等待"等待"通过循环直到轮到他们
答案 0 :(得分:2)
您的进程都拥有与相同内核维护的打开文件描述相关联的流。这些流的缓冲区属于进程,但文件偏移属于底层的打开文件描述。
每当进程从没有数据缓冲的流中读取时,它很可能会将更多数据读入缓冲区,而不是立即使用它。这就是你的情况。读取的第一个进程将文件的所有36个字节读入其流缓冲区的副本,将基础文件偏移推进到文件末尾。之后尝试从流中读取的进程不共享第一个流的缓冲区;他们只看到(共享)文件偏移量位于文件末尾。
如果您希望多个进程从同一个文件中协同读取,那么您需要考虑到这一点。我至少可以看到两种机制:
在共享内存段中,您还要保留到目前为止消耗的字节数。在尝试阅读之前,每个流程都使用它来执行fseek()
到适当的位置。
您使用带有文件描述符(open()
,read()
)的低级I / O而不是流I / O.如果执行任何缓冲,则将缓冲区维护在共享内存中。
另请注意,您需要某种形式的同步,以确保每个进程都可以看到由其他进程执行的对共享内存的写入。您可以通过创建并正确使用进程共享的互斥锁和条件变量来为和提供摆脱浪费的自旋锁。