2

Inside my code I want to...

1) the parent process will create an array with at least 10 element

2) the child process will calculate the production of all elements with odd index inside the array

3) the child process will provide the result to the parent process when it finish calculation and then the child process will terminate

4) the parent will calculate the production after it get the result from the child process

5) the parent process will finally output the results.

Now the CODE LOGIC is easy to write which is down below

int cal(int arr[10]) {
    int i=0;
    int sum = 0;
    for (i=1; i<10; i=i+2) {
        sum = sum + arr[i];
    }

    return sum;
} // end of calc

int main() {
    int arr[] = { 10, 20, 25, 5, 6, 45, 87, 98, 23, 45};
    int sum = cal(arr);

    printf("Sum of all odd indexs element is : %d", sum);

    return 0;
} // end of main

And here is the code for creating a child process using fork()

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    pid t pid;
    /* fork a child process */
    pid = fork();
    if (pid < 0) { /* error occurred */
        fprintf(stderr, "Fork Failed");
        return 1;
    }
    else if (pid == 0) { /* child process */
        execlp("/bin/ls","ls",NULL);

    }
    else { /* parent process */
        /* parent will wait for the child to complete */
        wait(NULL);
        printf("Child Complete");
    }
    return 0;
} // end of main

My questions are...

  • How would I use the CODE LOGIC and combine it with creation of the child process using fork()? If the pid == 0, then the creation of a child process was successful so I think that is where we insert the code for step 2... 2) the child process will calculate the production of all elements with odd index inside the array.

  • How would the parent send the array to the child process so that the child process could sum the elements with odd index?

UPDATED CODE: I combined both codes above into one

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>

/*
calculate the production of all elements with odd index inside the array
*/
int cal(int arr[10]) {
    int i=0;
    int sum = 0;
    for (i=1; i<10; i=i+2) {
        sum = sum + arr[i];
    }

    return sum;
} // end of calc

int main() {
    pid t pid;
    /* fork a child process */
    pid = fork();
    if (pid < 0) { /* error occurred */
        fprintf(stderr, "Fork Failed");
        return 1;
    }
    else if (pid == 0) { /* child process */
        print("I am the child process");
        // the child process will calculate the production 
        // of all elements with odd index inside the array
        calc();
        // the child process will provide the result to the parent process 
        // when it finish calculation and then the child process will terminate
        exit(0);

    }
    else { /* parent process */
        /* parent will wait for the child to complete */
        printf("I am the parent, waiting for the child to end");
        // the parent process will create an array with at least 10 element
        int arr[] = { 1, 2, 5, 5, 6, 4, 8, 9, 23, 45 };
        int sum = calc(arr);
        wait(NULL);
        printf("Child completed calculating the production of all elements with odd index inside the array");
        // the parent will calculate the production after it get the result from the child process
        // the parent process will finally output the results.
        printf("Sum of all odd indexs element is : %d", sum);
    }
    return 0;
} // end of main
asilvester635
  • 81
  • 2
  • 13
  • So, right now you're only passing `argv[0]` with `ls`. If you want to pass more arguments, ...put them on the command line. That is: `execlp("/path/to/your/executable", "argument-that-becomes-$0", "argument-that-becomes-$1", "argument-that-becomes-$2", "etc", NULL)`. – Charles Duffy Oct 04 '17 at 22:02
  • To communicate between 2 process, you can use signals (`kill()` and `signal()` or `sigaction()`) – YaatSuka Oct 04 '17 at 22:05
  • @YaatSuka, eh? The OP doesn't just want to send a (non-information-carrying) signal, they want to pass explicit values. Signals don't have guarantees about delivery order, and several of them have meanings that can't be overridden (you can't pass `9` via a `SIGKILL` and have the program interpret in any way other than as a command to exit, so it's useless as a way to send an integer with an unknown value). – Charles Duffy Oct 04 '17 at 22:06
  • Possible duplicate of [passing integer arguments when using execve](https://stackoverflow.com/questions/3446257/passing-integer-arguments-when-using-execve) – Charles Duffy Oct 04 '17 at 22:06
  • @CharlesDuffy you can pass explicite values by signals... – YaatSuka Oct 04 '17 at 22:07
  • @YaatSuka, not in the general case. You can perhaps decide ahead-of-time that `SIGUSR1` means `2` and `SIGUSR2` means `3`, but there are very few signals to work with, and you can't usefully/meaningfully combine them due to the lack of guarantees about delivery ordering. – Charles Duffy Oct 04 '17 at 22:08
  • @CharlesDuffy There are lots of way to send values with signals.. I created a battleship game with binary communication just with signals, so you can do what you want – YaatSuka Oct 04 '17 at 22:09
  • @YaatSuka, note what I said about the lack of guaranteed ordering. If you try to build a protocol on top of an unreliable communication mechanism, then you're relying on chance for your software to work (especially when the system is under heavy load and may not be scheduling delivery as often as you expect). This might be feasible for a toy, but it's not something we should be teaching as a best practice. – Charles Duffy Oct 04 '17 at 22:10
  • @CharlesDuffy If you encrypt the data and you know what you're doing, you can decrypt it and have relevant value (you just have to think about how you want to communicate with signals, as I said there are lots of way to do that) – YaatSuka Oct 04 '17 at 22:14
  • @asilvester635, there is another way: Use global variables. If the child process set a global variable, you can get its value after with the parent ;) – YaatSuka Oct 04 '17 at 22:16
  • @YaatSuka, encryption makes things *worse*, not better: It increases the amount of data that needs to be passed in-order without any permutation to allow any useful content to be interpreted from same. – Charles Duffy Oct 04 '17 at 22:17
  • @YaatSuka, and... err, what? If you `fork()`, a child gets a copy of any global variable, yes, but that's a distinct copy in a copy-on-write memory segment: As soon as the child changes its copy, it gets reallocated to a different physical page rather than shared with the parent, so the parent can't see it. And when you call any `exec`-family function, all your variables' prior values are thrown away. I'm starting to wonder if I'm being trolled. – Charles Duffy Oct 04 '17 at 22:19
  • Ahah ok @CharlesDuffy, I think you're good in C, but I know what I'm saying, I created a game based on signals and processes and I know that global variables are shared by each process – YaatSuka Oct 04 '17 at 22:22
  • 2
    @YaatSuka, global variables are *absolutely not* shared between processes. They're copied from parent to child, but not back from child to parent. The claim is simply and entirely untrue. Maybe you're thinking about *threads* instead of *processes*? – Charles Duffy Oct 04 '17 at 22:45
  • 1
    @YaatSuka, see [After forking, are global variables shared?](https://stackoverflow.com/questions/4298678/after-forking-are-global-variables-shared) – Charles Duffy Oct 04 '17 at 22:47

2 Answers2

1

There are inter-process communication (IPC) mechanisms allowing you to pass information between processes.

As a rule, fork is the only way to create new processes in Unix-like systems. At that, child process inherits code and address space of parent. It means that child is a duplicate (in some degree, see link above) of parent at this point of time.

In modern Unix variants and in Linux, fork is implemented using copy-on-write pages. It just means that when parent or child process tries to modify shared memory page, operating system creates a copy of this page. Now parent and child have own memory page.

System call exec replaces the current process image with a new process image. It means that parent and child processes wouldn't share any memory pages or code now.

In your program you shouldn't call execlp(). Use advantages of copy-on-write mechanism. So do fork() in the main() function in your CODE LOGIC program after defining the arr. Then access arr from the child process. Use wait() system call to make parent is blocked until child doesn't finish.

You should use IPC to return result from the child process. In your case pipes are the best choice. But it's obvious you do lab assignment about Unix processes, and not about IPC. So you may return result via exit code of child process. Pass result to the exit() function. Note that you can pass only 8 bits (see comments under my answer).

This is a working code:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int calc(int *arr, int n) {
    int sum = 0;
    for (i = 1; i < n; i += 2) {
        sum = sum + arr[i];
    }
    return sum;
}

int main(void) {
    int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int n = sizeof(arr) / sizeof(arr[0]);

    pid_t pid = fork();
    if (pid < 0) {
        perror("fork failed");
        return 1;
    }
    else if (pid == 0) {
        printf("I am the child process\n");

        int child_sum = calc(arr, n);
        exit(child_sum);
    }
    else {
        printf("I am the parent process\n");

        int parent_sum = calc(arr, n);

        int child_sum;
        if (wait(&child_sum) == -1) {
            perror("wait failed");
        }
        else {
            printf("Sum by child: %d\n", child_sum);
        }

        printf("Sum by parent: %d\n", parent_sum);
    }

    return 0;
}
boriaz50
  • 860
  • 4
  • 17
  • 2
    The exit status is a poor choice for the child process to deliver its computed result to its parent, because only 8 bits are available there for its use (on a POSIX-conformant system, but we seem to be assuming POSIX or similar by using `fork`, `wait`, and `unistd.h`). The OP's result could easily be too large for that. – John Bollinger Oct 04 '17 at 22:37
  • Thank you very much for useful comment for me. – boriaz50 Oct 04 '17 at 22:43
  • 1
    The usual practice for reading results from a child process is to set up a FIFO pair so the child can write results to the FIFO and close it, and the parent can read and interpret them. This is what `variable=$(somecommand)` in shell does, for example. – Charles Duffy Oct 04 '17 at 22:48
  • Do you mean pipes? – boriaz50 Oct 04 '17 at 22:49
  • Yes. Pipes *are* FIFOs ("first-in, first-out"). – Charles Duffy Oct 04 '17 at 22:52
  • @CharlesDuffy I have mentioned it in answer. What do you think about shared memory? – boriaz50 Oct 04 '17 at 22:55
  • A bit of a pain to manage (it's easy to leak SHM segments if exiting uncleanly), and vast overkill for present purpose. As a sysadmin, if I have to run `ipcrm` one more time, it'll be once too many. – Charles Duffy Oct 04 '17 at 22:57
  • @boriaz50 Hey, I've updated my code. My intention is to pass the arr array that I've created from my parent process to the child process, and invoke the calc method in my child process, which calculates the production of all elements with odd index inside the array. The sum is then returned by the calc method back to child process, and the child process will send the sum back to parent process. Is this possible? – asilvester635 Oct 04 '17 at 23:17
0

Here execlp will give your child process a new address space. So you practically can't send an argument to the child process from parent process. But you can do as follows,

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    pid_t pid;
    /* fork a child process */
    pid = fork();
    int sum = 0;
    int arr[] = { 10, 20, 25, 5, 6, 45, 87, 98, 23, 45};
    if (pid < 0) { /* error occurred */
        fprintf(stderr, "Fork Failed");
        return 1;
    }
    else if (pid == 0) { /* child process */
        int i=0;

        for (i=1; i<10; i=i+2) {
            sum = sum + arr[i];
        }

        return sum;


    }
    else { /* parent process */
        /* parent will wait for the child to complete */
        wait(NULL);

    int i=0;

        for (i=1; i<10; i=i+2) {
            sum = sum + arr[i];
        }

        printf("%d\n",sum);
    }
    return 0;
}

ps- Here the array is declared after the fork() so it is common to both parent and child processes.

MLPJ
  • 108
  • 1
  • 12