3

前段时间,我使用 pthread 为哲学家就餐问题编写了一个 C 程序,现在正尝试将其更改为使用 fork()。这是我已经通过的讲座的练习。但是一个朋友向我寻求帮助,我似乎无法自己弄清楚,这让我发疯了!

如果我做一个“ps”,那么进程就在那里。但是标准输出没有任何输出,所以我认为我在管道上做错了。

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>

#define N 5     
#define LEFT (i+4)%N
#define RIGHT (i+1)%N
#define THINKING 0
#define HUNGRY 1
#define EATING 2

sem_t spoon;
sem_t phil[N];
int state[N];
int phil_num[N]={0,1,2,3,4};
int fd[N][2]; // file descriptors for pipes
pid_t pid, pids[N]; // process ids
int i; 
int num;

void philosopher(int i);
void test(int i);
void take_spoon(int i);
void put_spoon(int i);

char buffer[100];

int main(void) 
{
  for(i=0;i<N;++i)
  {
    pipe(fd[i]);        
    pids[i] = fork();

    printf("i=%d\n",i);
    printf("pids[i]=%d\n",pids[i]);

    if(pids[i]==0)
    {
      // child
      dup2(fd[i][1],1);
      close(fd[i][0]);      
      close(fd[i][1]);
      philosopher(i);
      _exit(0);
    }

    else if(pids[i]>0)
    {
      // parent
      dup2(fd[i][0],0);
      close(fd[i][0]);      
      close(fd[i][1]);
    }
  }

  // wait for child processes to end
  for(i=0;i<N;++i) waitpid(pids[i],NULL,0);

  return 0;
}



void philosopher(int i)
{
  while(1)
  {
    sleep(1);
    take_spoon(i);
    sleep(2);
    put_spoon(i);
    sleep(1);
  }
}

void take_spoon(int i)
{
  sem_wait(&spoon);
  state[i] = HUNGRY;
  printf("philosopher %d is hungry\n",i+1);
  test(i);
  sem_post(&spoon);
  sem_wait(&phil[i]);
}

void put_spoon(int i)
{
  sem_wait(&spoon);
  state[i] = THINKING;
  printf("philosopher %d puts down spoon %d and %d hin\n",i+1,LEFT+1,i+1);
  printf("philosopher %d thinks\n",i+1);
  test(LEFT);
  test(RIGHT);
  sem_post(&spoon);
}

void test(int i)
{
  if( state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING)
  {
    state[i] = EATING;
    printf("philosopher %d takes spoon %d and %d\n",i+1,LEFT+1,i+1);
    printf("philosopher  %d eats\n",i+1);
    sem_post(&phil[i]);
  }
}

预先感谢您的任何帮助。

4

1 回答 1

5

几个问题。首先是在 之后fork(),子进程和父进程不共享内存。这是线程和进程之间的主要区别之一。每个进程都有自己的虚拟地址空间。无论你想让哲学家们分享什么,你都必须通过创建共享内存来明确地做到这一点。看来您打算在所有进程之间共享全局变量。(请注意,有些东西是共享的,例如打开的文件描述符,并且子进程确实从父进程那里获得了变量的副本,初始化为fork()调用时分配给它们的值。)

其次,你有一些令人困惑的不必要的变量。特别是,管道没有任何实际用途。每个stdout进程都将进入控制台屏幕,而无需尝试将它们通过管道传回父进程。这是因为子进程已经继承了父进程的打开文件描述符,所以子进程已经使用与父进程相同的文件描述符stdout。此外,phil_numnum变量未使用,而i. 变量似乎不必要地变成了全局变量pidpids

第三,您未能初始化信号量。作为全局变量的默认初始化可能会使信号量“可用”但初始值为 0,这意味着sem_wait()它只会阻塞。在您的情况下,您需要共享内存中的这些信号量,因此无论如何调用sem_init()是强制性的(表明它将在多个进程之间共享),并且该调用使您有机会使用值正确初始化信号量1so初始sem_wait()呼叫有机会返回。

在将全局变量调整为真正需要共享的内容后,可以将它们捆绑在一起形成一个结构。然后,可以为共享数据创建一个全局指针。

struct shared_data {
  sem_t spoon;
  sem_t phil[N];
  int state[N];
};

struct shared_data *shared;

void initialize_shared(); /* at program start */
void finalize_shared();   /* at program end */

创建共享内存的一种方法是使用mmap(). 创建内存后,应正确初始化数据。这包括sem_init()对信号量的调用。sem_destroy()用于清理信号量,映射的内存可以用munmap(). 这些是在进程退出时为您完成的,但为了完整性而提供。(您应该始终检查您进行的所有操作系统调用的返回值,但为了简洁起见,我省略了它们。)

void initialize_shared()
{
  int i;
  int prot=(PROT_READ|PROT_WRITE);
  int flags=(MAP_SHARED|MAP_ANONYMOUS);
  shared=mmap(0,sizeof(*shared),prot,flags,-1,0);
  memset(shared,'\0',sizeof(*shared));
  sem_init(&shared->spoon,1,1);
  for(i=0;i<N;++i) sem_init(&shared->phil[i],1,1);
}

void finalize_shared()
{
  int i;
  for(i=0;i<N;++i) sem_destroy(&shared->phil[i]);
  munmap(shared, sizeof(*shared));
}

你的main()实现并没有真正改变,除了你需要为那些不必要的全局变量添加局部变量,以及 callinitialize_shared()和 optional finalize_shared()。此外,删除所有与pipe().

int main(void)
{
  int i;
  pid_t pid, pids[N]; // process ids
  initialize_shared();
  for(i=0;i<N;++i)
  {
    pid = fork();
    if(pid==0)
    {
      // child
      philosopher(i);
      _exit(0);
    }
    else if(pid>0)
    {
      // parent
      pids[i] = pid;
      printf("pids[%d]=%d\n",i,pids[i]);
    }
    else
    {
      perror("fork");
      _exit(0);
    }
  }
  // wait for child processes to end
  for(i=0;i<N;++i) waitpid(pids[i],NULL,0);

  finalize_shared();
  return 0;
}

请注意,您的程序永远不会真正自行退出,因为philosopher()它是作为无限循环实现的。

于 2013-06-13T19:25:29.083 回答