编译错误的文件?

时间:2018-10-30 20:21:56

标签: c makefile fork shared-memory

我有3个文件-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

2 个答案:

答案 0 :(得分: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函数返回了两次:一次返回到父进程,在该子进程中它返回子进程的pid,一次返回到子进程,在该子进程中它返回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++;
}

答案 1 :(得分:2)

是什么让您认为Fish在SwimMill之前奔跑?

如果您依赖于输出到stdout的顺序,则会被"hello"的缓冲所迷惑,直到写'\n'fflush(stdout)之前,缓冲printf("Hello"); 才立即输出调用,否则过程终止。

也就是说SwimMill首先运行,而Fish首先显示输出。

更改:

printf("Hello\n");

printf("printing from fish");

类似地:

printf("printing from fish\n");

system.windows.control.images