0

I have this assignment where I have to create two processes and each process has to generate 50 integers which are odd or even.

Write a simple sequence-number system through which two processes, P1 and P2, can each obtain 50 unique integers, such that one receives all the odd and the other all the even numbers. Use the fork() call to create P1 and P2. Given a file, F, containing a single number, each process must perform the following steps:

a. Open F.
b. Read the sequence number N from the file.
c. Close F.
d. Output N and the process' PID (either on screen or test file).
e. Increment N by 1
f. Open F.
g. Write N to F.
h. Flush F.
i. Close F

As suggested by SO user I have created a loop in each process and ran the steps as mentioned above. But I am not sure if this approach is correct. I have asked my Teaching assistant for help and he suggested to do the same(using sleep call and waiting for a valid integer). But the thing is I can obtain the same results without using the sleep call. So I am not sure if I am applying the logic properly to code. Can someone please help?

This is my implementation:

void getUniqueNumbers() {

    struct process p1;
    struct process p2;
    int numberFromFile;

    pid_t pid = fork();

    // Process 1
    if (pid == 0) {

        int p1Counter = 0;
        p1.processId = getpid();

        while(p1Counter < numLimit) {
            numberFromFile = getNumberFromFile();
            if (numberFromFile % 2 == 0) { // even
                p1.numbers[p1Counter] = numberFromFile;
                printf("N: %d, PID: %d\n", numberFromFile, p1.processId);
                numberFromFile++;
                writeNumberToFile(numberFromFile);
                p1Counter++;
            }
            else {
                sleep(1);
            }

        }

    }
    // Process 2
    else if (pid > 0 ) {

        int p2Counter = 0;
        p2.processId = getpid();

        while(p2Counter < numLimit) {
            numberFromFile = getNumberFromFile();
            if (numberFromFile % 2 != 0) { // odd
                p2.numbers[p2Counter] = numberFromFile;
                printf("N: %d, PID: %d\n", numberFromFile, p2.processId);
                numberFromFile++;
                writeNumberToFile(numberFromFile);
                p2Counter++;
            }
            else {
                sleep(1);
            }
        }

    }
    else {
        printf("Error: Could not create process\n");
    }

}

Read/Write functions:

// Returns the number included in user provided file
int getNumberFromFile() {

    FILE *fp = fopen(fileName, "rb");
    int num = 0;

    if (fp != 0) {
        char line[10];
        if (fgets(line, sizeof(line), fp) != 0)
            num = atoi(line);
        fclose(fp);
    }

    return num;

}

// Writes a given number to the user provided file
void writeNumberToFile(int num) {

    FILE *fp = fopen(fileName, "w");

    if (fp != 0) {
        fprintf(fp, "%d", num);
        fclose(fp);
    }

}
Community
  • 1
  • 1
ChaniLastnamé
  • 493
  • 4
  • 9
  • 19

1 Answers1

0

The code looks ok. It can be simplified a lot though.

void getUniqueNumbers()
{
  struct process p;       // We need only 1 structure
  size_t counter = 0;     // sample counter
  int    oddEven;         // flag if we are parent
  pid_t pid = fork();     // Fork here
  if (-1 == pid)
  {
    abort(); // simply die on error
  }

  oddEven = 0 == pid ? 0 : 1;
  p.processId = getpid(); // We are either child or parent.

  while (counter < numLimit)
  {
    int numberFromFile = getNumberFromFile();
    if ((numberFromFile & 1) == oddEven)
    {
      p.numbers[counter++] = numberFromFile;
      printf("N: %d, PID: %ld\n", numberFromFile, (long)p.processId);
      numberFromFile++;
      writeNumberToFile(numberFromFile);
    }
    sleep(1); // sleep in both cases
    // Extra check for parent: if child has died, we are in infinite
    // loop, so check it here
    if (0 != pid && counter < numLimit)
    {
      int status = 0;
      if (waitpid(pid, &status, WNOHANG) > 0)
      {
        printf("Child exited with 0x%08X status\n", status);
        break;
      }
    }
  }

  // wait till child process terminates
  if (0 != pid)
  {
    int status = 0;
    waitpid(pid, &status, 0);
    printf("Child exited with 0x%08X status\n", status);
  }
}

Also, the file reading/writing either should use file lock operations, or atomic file change. It is important to prevent potential errors like one thread is writing number 40006, and another one manages to read 400. Should not happen in real life though.

File locks are needed to prevent concurrent access to the same contents. It can be exclusive lock, or shared read exclusive write.

Atomic modifications are feature that enables to replace file contents atomically, regardless of how many operations it took to write the data. It is an alternative to keep data consistent.

Valeri Atamaniouk
  • 5,125
  • 2
  • 16
  • 18