编译错误的文件?

8
我有三个文件——SwimMill.cFish.cPellets.c,每个文件都被编译成可执行文件。当运行SwimMill时,它使用fork()exec()来运行FishPellets。但是,出现了一个问题,我在终端中使用make编译程序并运行SwimMill时,文件Fish先运行。有谁能帮帮我吗?

Makefile

all: SwimMill Fish Pellets

SwimMill: SwimMill.c
    gcc -o SwimMill SwimMill.c

Fish: Fish.c
    gcc -o Fish Fish.c -lm

Pellets: Pellets.c
    gcc -o Pellets Pellets.c

SwimMill.c

// Uses both fish and pellets, 30 seconds, then print it out
// Create pellets at random intervals, from 0x80
// Eating --> Get rid of most significant bit
// Use shared memory for fish and pellet position only
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#define SHM_SIZE 1000

/*
TODO: SwimMIll FIRST, draw and get everything working
*/

/* 1. Create share memory using shmget
2. Attach to shared memory using shmat
3. Do operations
4. Detach using shmdt
*/

void printGrid(int*);
void handler(int);

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

    printf("Hello");
    signal(SIGINT, handler);

    key_t key;
    int shmid;
    int *shm;
    int timer = 0;
    int fish = 0;
    int pellet[20];

    key = ftok("SwimMill.c", 'b'); //generate random ke
    shmid = shmget(key, SHM_SIZE, IPC_CREAT|0666);
    shm = shmat(shmid, NULL, 0); // Attach

    // Initializing the shared memory to prevent segmentation fault
    for (int i = 0; i < SHM_SIZE; i++){
        shm[i] = -1;
    }

    int index = 0;
    while(timer <= 30){
        sleep(1); // Slow process down
        fish = fork();
        execv("Fish", argv);
        pellet[index] = fork();
        execv("Pellets", argv);
        printGrid(shm);
        printf("\n");
        timer++;
        index++;
    }

    shmdt(shm);
    shmctl(shmid, IPC_RMID, NULL);
    printf("Program finished! \n");
    getchar(); // Pause consol
    return 0;
}

void printGrid(int* shm) {
    int row = 10;
    int column = 10;
    char stream[row][column]; //2D Dimensional array, fish can only move last row of 2d


    //Initializing grid first
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < column; j++) {
            stream[i][j] = '~';
        }
    }

    //Printing out grid with fish and pellet
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < column; j++) {
            stream[i][j] = '~'; // water
            for (int k = 0; k < 20; k++) {
                stream[shm[k]/10][shm[k]%10] = 'O'; // pellets
                stream[shm[0]/10][shm[0]%10] = 'Y'; // Fish
            }
            printf("%c ", stream[i][j]   );
        }
        printf("\n");
    }

}

void handler(int num) {
    perror(" Interrupt signal is pressed!! \n");
    exit(1);
}

Fish.c

// 1 fish
// Scan the entire array, and focus on one pellet
// Arrange itself

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <math.h>
#include <unistd.h>

int findClosestPellet(int*);
void moveLeft(int, int*);
void moveRight(int, int*);

int main() {
  printf("printing from fish");
  key_t key = ftok("SwimMill.c", 'b');
  int shmid = shmget(key, 1024, IPC_CREAT|0666);
  int *shm = (int*) shmat(shmid, NULL, 0);

  int fish = 94; // Middle position
  shm[0] = fish; // Store first shared memor space to fish
  int columnToMoveTo = 0;
  while(1) {
    int closestPellet = shm[findClosestPellet(shm)];
    if ((closestPellet % 10) > (fish % 10) ) {
      moveRight(fish, shm);
    }
    else if ((closestPellet % 10) < (fish % 10)) {
      moveLeft(fish, shm);
    }
    sleep(1);
  }
  shmdt(shm);
  return 0;
}

int findClosestPellet(int* shm) {
  // Using distance formula to find closest pellet
  // (x2 - x1)^2 + (y2 - y1)^2
  int closestPellet = 0;
  int distance[20] = {0}; // Distance of all 20 pellets
  int minimumDistance = 0;
  // shm[1] = 11;
  // shm[2] = 14;
  // shm[3] = 10;
  // shm[4] = 55;
  int x2 =  shm[0] % 10;
  int y2 = shm[0] / 10;
  for (int i = 1; i < 20; i++) {
    int x1 = shm[i] % 10;
    int y1 = shm[i] / 10;
    distance[i] = pow(x2-x1,2) + pow(y2-y1,2); // Storing them
  }
  minimumDistance = distance[1];

  //Finding smallest distance
  for (int i = 2; i < 20; i++) {
    if (distance[i] <= minimumDistance) {
      closestPellet = i;
    }
  }
  printf("Closest pellet %d \n", closestPellet);
  return shm[closestPellet];
}

void moveLeft(int fish, int* shm) {
  if (shm[0] <= 90) {
  }
  else{
    fish--;
    shm[0]--;
  }
}

void moveRight(int fish, int* shm) {
  if (shm[0] >= 99){
  }
  else{
    fish++;
    shm[0]++;
  }
}

Pellets.c

// Multiple pellets
//Process ID, position, eaten/misse
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>

void eatPellet();
void missPellet();

int main() {
  key_t key = ftok("SwimMill.c", 'b');
  int shmid = shmget(key, 1024, IPC_CREAT|0666);
  int *shm = (int*) shmat(shmid, NULL, 0);

  int i = 1; // 1 - 19 are pellets
  for (; i < 20; i++) {
    int pelletPosition = rand() % 9 + 0; // random number from 0 - 9
    shm[i] = pelletPosition;
    break;
  }
  while(1) {
    if (shm[i] < 90) {
      shm[i] += 10;
    }
    else if (shm[i] == shm[0]) {
      eatPellet();
      printf("Position: %d\n", shm[i] );
      break;
      // EATEN and KILL
    }
    else {
      // KIll process, terminate
      missPellet();
      printf("Position: %d\n", shm[i] );
      break;
    }
    // printf("%d\n",shm[i] );
    i++;
    sleep(1);
  }
  shmdt(shm);
  return 0;
}

void eatPellet() {
  printf("Pellet eaten!");
  printf("PID: %d \n", getpid());

}

void missPellet() {
  printf("Pellet missed");
  printf("PID: %d \n", getpid());
}

对于makefile,我运行“make”。然后我运行./SwimMill。但是,由于某种原因它运行了Fish

可能是 C/C++中两个'主函数' 的重复问题。 - erik258
尽管这是一个重复的问题,但是这是我最近看到的最高质量的问题。我赞扬你包含了所有相关的材料。如果没有它们,我从来没有想过你可能会定义多个main函数。 - erik258
@DanFarrell 感谢您的回复。然而,我的程序每个文件只有一个主要函数。您向我展示的链接在一个文件中有多个主要函数的情况下存在问题。这是否相关? - Slay
1
@DanFarrell 嗯?他没有将它们链接在一起。这不是问题。 - Rafael
是的,我会编辑掉那部分内容,抱歉。 - erik258
显示剩余2条评论
2个回答

9

您没有正确使用fork / exec

while(timer <= 30){
    sleep(1); // Slow process down
    fish = fork();
    execv("Fish", argv);
    pellet[index] = fork();
    execv("Pellets", argv);
    printGrid(shm);
    printf("\n");
    timer++;
    index++;
}

需要注意的是,fork 函数会返回两次:一次在父进程中返回子进程的 ID,另一次在子进程中返回 0。

你正在创建一个新进程,但没有检查返回值。因此,子进程父进程都调用了 execv 来启动“Fish”程序,所以你有两个“Fish”运行实例而没有“SwimMill”运行。

你需要检查 fork 的返回值,以确定该进程是父进程还是子进程,并采取相应的措施。

while(timer <= 30){
    sleep(1); // Slow process down
    fish = fork();
    if (fish == -1) {
        perror("fork failed");
        exit(1);
    } else if (fish == 0) {
        execv("Fish", argv);
        perror("exec failed");
        exit(1);
    }

    pellet[index] = fork();
    if (pellet[index]== -1) {
        perror("fork failed");
        exit(1);
    } else if (pellet[index] == 0) {
        execv("Pellets", argv);
        perror("exec failed");
        exit(1);
    }

    printGrid(shm);
    printf("\n");
    timer++;
    index++;
}

非常感谢关于fork的帮助!段错误不再发生。但是,我仍然无法运行SwimMill.c!Fish.c先被运行了。这是程序还是我的VM Linux的问题? - Slay
@Slay首先运行它是因为你先启动了它。因为你在同一个终端中同时运行多个进程,它们的输出会交错在一起。 - dbush
我有点理解,但并不是很清楚。所以你的意思是我需要发送一些信号来终止进程,以便运行正确的进程? - Slay
@Slay 我的意思是你正在运行正确的进程。只是因为两个进程同时运行并且同时写入终端,所以看起来不像。 - dbush

2

你为什么认为Fish在SwimMill之前运行?

如果你依赖stdout输出的顺序,你会被"hello"的缓冲所误导。只有当写入'\n'、调用fflush(stdout)或进程终止时,它才会立即输出。

也就是说,SwimMill确实先运行,但Fish先显示输出。

修改为:

printf("Hello");

to

printf("Hello\n");

同样地:
printf("printing from fish");

to

printf("printing from fish\n");

这完全解释了我的困惑。谢谢! - Slay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接