Author Topic: [C] child processes  (Read 2452 times)

0 Members and 1 Guest are viewing this topic.

Offline Deque

  • P.I.N.N.
  • Global Moderator
  • Overlord
  • *
  • Posts: 1203
  • Cookies: 518
  • Programmer, Malware Analyst
    • View Profile
[C] child processes
« on: October 24, 2011, 10:26:45 pm »
Hi guys,

here are some code samples that show you how to use child processes in C.

The following program creates a child process. The parent process computes primes to 5000000, the child process prints out the own PID and that of the parent and afterwards computes primes up to 4000000. Only every 2000. prime is printed, the PID of the process is printed along with the primes.

The parent process waits for the child after it is done. It prints the childs PID and exit status in the end.

If you use gcc you have to do this to compile (-lm because it needs the math library):

Quote
gcc -Wall -o childprim childprim.c -lm

Code for childprim.c

Code: [Select]
#include <stdio.h>
#include <math.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

void prime_output(long n);
short is_prime(long p);

int main(){
    int status;
    pid_t pid;
    pid = fork();

    switch(pid){
    case -1:   
        perror("fork");
        return 2;
    case 0:       
        printf("child-PID: %d \t my parent: %d\n", getpid(), getppid());
        prime_output(5000000);
        return 1;
    default:   
        printf("parent-PID: %d \n", getpid());
        prime_output(4000000);
        printf("parent waiting for child\n");
        while((pid = wait(&status))>0){
            printf("child-PID = %d, status |%x|%x|\n",
                pid, (status>>8) & 0xFF, status & 0x7F);
        }
        return 0;
    }
}

void prime_output(long n){
    long i, anz=0;
    for ( i = 2; i <= n; i++ )
        if ( is_prime(i) ) {
            anz++;
            if(anz%2000 == 0){ //print every 2000. prime
                printf ("%d: %ld \n", getpid(), i);
            }
        }
    printf ("\n%ld primes\n", anz);
}

short is_prime(long p){
    long s, d;
    s = (long) sqrt(p) + 1;
    if ( p <  2 ) return 0;
    if ( p == 2 ) return 1;
    if ( p % 2 == 0 ) return 0;
    for ( d = 3; d <= s; d+=2 )
        if ( p % d == 0 ) return 0;
    return 1;
}

Now this is one file that contains the whole code for child and parent. You might want to put the child's code in another file and you also might want to start more than one child.
This time two child processes are created. Each child executes the code in prim.c. The parent waits for both childs to be finished.

Two arguments are possible: 1. the maximum for the primes generation and 2. the distance at which the primes are printed. If you don't use arguments the program asks you for the values. Those values are passed as arguments to the prim.c code.

Here is childprim2.c

Code: [Select]
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

int main(int argc, char **argv){
    int status, i, distance;
    long max;
    pid_t pid;
    char filename[] = "prim";
    char *argv_child[4], arg1[10], arg2[10];

    switch(argc){
    case 1:   
        printf("maximum:\n");
          scanf("%ld", &max);
        while (getchar() != '\n') { }
        printf("distance:\n");
          scanf("%d", &distance);
        while (getchar() != '\n') { }
        break;
    case 2:   
        max = atoi(argv[1]);
          printf("distance:\n");
          scanf("%d", &distance);
        while (getchar() != '\n') { }
        break;
    default:   
        max = atoi(argv[1]);
          distance = atoi(argv[2]);
        break;
    }

    sprintf(arg2, "%d", distance);
    sprintf(arg1, "%ld", max);
    argv_child[0] = filename;
    argv_child[1] = arg1;
    argv_child[2] = arg2;
    argv_child[3] = NULL;

    for(i = 0; i < 2; i++){
        if((pid = fork()) == 0){
            printf("execute execv\n");
            execv(filename, argv_child);
            perror("error execv\n");
        }
    }

    while((pid = wait(&status)) > 0){
        printf("wait for child \n");
        printf("child-PID = %d, status |%x|%x|\n",
            pid, (status>>8) & 0xFF, status & 0x7F);
    }
    printf("parent exit \n");
    return 0;
}

This is prim.c, the code that is executed by the child processes.

Code: [Select]
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <unistd.h>

void prime_output(long n1, int n2);
short is_prime(long p);

int main(int argc, char **argv){
    long max = atoi(argv[1]);
    int distance = atoi(argv[2]);
    prime_output(max, distance);
    return 1;
}

void prime_output(long max, int distance){
    long i, anz=0;
    for ( i = 2; i <= max; i++ )
        if ( is_prime(i) ) {
            anz++;
            if(anz%distance == 0){
                printf ("%d: %ld \n", getpid(), i);
            }
        }
    printf ("\n%ld primes\n", anz);
}

short is_prime(long p){
    long s, d;
    s = (long) sqrt(p) + 1;
    if ( p <  2 ) return 0;
    if ( p == 2 ) return 1;
    if ( p % 2 == 0 ) return 0;
    for ( d = 3; d <= s; d+=2 )
        if ( p % d == 0 ) return 0;
    return 1;
}

The makefile to compile both files:
Code: [Select]
all: childprim2 prim
prim: prim.o
    gcc -Wall -o prim prim.o -lm
childprim2: childprim2.o
    gcc -Wall -o childprim2 childprim2.o
childprim2.o: childprim2.c
    gcc -Wall -c childprim2.c
prim.o: prim.c
    gcc -Wall -c prim.c

A sample output:

Quote
[deque@desolate childprim2]$ ./childprim2
maximum:
500000
distance:
20000
execute execv
execute execv
1333: 224737
1332: 224737
1333: 479909
1332: 479909

41538 primes
wait for child
child-PID = 1333, status |1|0|

41538 primes
wait for child
child-PID = 1332, status |1|0|
parent exit

If you see anything that is a bad habit please tell me. I am not as familiar with C as I am with Java.

Deque

Edit: The code should work for Unix and Linux.
« Last Edit: October 25, 2011, 09:34:53 am by Deque »

Offline xzid

  • Knight
  • **
  • Posts: 329
  • Cookies: 41
    • View Profile
Re: [C] child processes
« Reply #1 on: October 25, 2011, 02:44:02 am »
....

If you see anything that is a bad habit please tell me. I am not as familiar with C as I am with Java.

function declarations of wait, atoi, getpid. linker will find the functions anyway, but gcc won't be able to tell you if you're using it wrong. By which I mean if you did:

atoi(22, "xxxxx", 3.14);

the program would compile without even a warning and you'd get a segfault when atoi tries to access address 0x16(22). Although once declared(#include <stdlib.h>) you'll get a warning:

Code: [Select]
atoi.c: In function ‘main’:
atoi.c:x: warning: passing argument 1 of ‘atoi’ makes pointer from integer without a cast
/usr/include/stdlib.h:148: note: expected ‘const char *’ but argument is of type ‘int’

To avoid such things use the -Wall(Warning all) switch on gcc, it'll tell you . Important option if you're beginning in C. If you ever have trouble locating a function or macro, try man'ing it, if fail grep is alot of help:

Code: [Select]
$ grep -r "extern.*atoi *(" /usr/include
/usr/include/pgsql/server/utils/builtins.h:extern int32 pg_atoi(char *s, int size, int c);
/usr/include/stdlib.h:extern int atoi (__const char *__nptr)

quick note about naming conventions:
  -> thisIsRare, ExceptSometimesLikeThis(mostly winAPI), cstyle, c_style

of course like any language, doesn't matter.

also i've never seen it called argvMain before, I feel the exec argument should be the one renamed. although you're free to call it what you want.

Apart from this I don't see any problems, maybe move sprintf + argv out of fork loop.

edit:

char *argv[10] is an array of length 10 holding (char*), setting it to 10(im assuming to fit arg1, arg2) isn't neccessary. Not copying data, only setting pointers. You only need *argv[4], try this:

Code: [Select]
  char *argv[10], argv2[4][10];
  printf("%d %d\n", sizeof(argv[0]), sizeof(argv2[0]));

http://www.antlr.org/wiki/display/CS652/How+To+Read+C+Declarations
« Last Edit: October 25, 2011, 03:18:45 am by xzid »

Offline Deque

  • P.I.N.N.
  • Global Moderator
  • Overlord
  • *
  • Posts: 1203
  • Cookies: 518
  • Programmer, Malware Analyst
    • View Profile
Re: [C] child processes
« Reply #2 on: October 25, 2011, 09:02:45 am »
Thanks a lot xzid. That is very helpful (+rep). I will correct the code as soon as possible.

Edit: Correction done.
« Last Edit: October 25, 2011, 09:35:33 am by Deque »