1

I have a problem, I need to write a small c program that prints out a random numbers given by three processes that are printing only one number by themselfes 20 times.

output should be something like 0122102021012021120... and something finishing from the parent process.

I only get outputs like:

00000000000000000000ready11111111111111111111readyready22222222222222222222readyreadyready

and I don't know what to do - it seems that I didn't understand the ground logic behind that fork() system ;)

my code is:

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4
  5 void printfXtimes(int a, int b){
  6         int i;
  7         for(i=0;i<b;i++){
  8                 printf("%i",a);
  9                 sleep(1);
 10         }
 11 }
 12
 13 void main(){
 14         for(int kid = 0; kid < 3; ++kid) {
 15                 int pid = fork();
 16                 if(pid < 0){
 17                         exit(EXIT_FAILURE);
 18                 }else if (pid > 0){
 19                          /* Parent process */
 20                         printf("ready");
 21                 }else{
 22                         /* Child process */
 23                         printfXtimes(kid,20);
 24                         exit(EXIT_SUCCESS);
 25                 }
 26                 for (int kid = 0; kid < 3; ++kid) {
 27                         int status;
 28                         pid_t pid = wait(&status);
 29                 }
 30
 31         }
 32 }

whats wrong here? :/ The task is considered "easy"... I don't get it...

Rasalas
  • 1,552
  • 2
  • 12
  • 15
  • 2
    When using `fork()`, the correct return type for `main()` is `int`, not `void`. You can use `void main()` on Windows; everywhere else, it is wrong (almost everywhere else — specific systems could document it as OK, like Windows does). See [What should `main()` return in C and C++?](http://stackoverflow.com/questions/204476/) – Jonathan Leffler May 24 '16 at 22:23
  • 1
    So why are you expecting `123123123`? I don't understand; fork really generates independent processes. There's no reason for one process to print a number, then wait for another thread, etc. It just does it's `for` loop, and eventually, the other threads get scheduled. Also, there's buffering on the output. At any rate, your code makes no attempt at making one process wait for the other, and it's pretty hard to do that correctly, indeed. Are you *sure* you're supposed to `fork` here, or were you given another hint on how to do synchronization between processes? – Marcus Müller May 24 '16 at 22:25
  • 1
    One problem is that after you launch each child, you wait for three children to die. That loop should probably be after the launch loop. Another problem is that you don't use newlines at the ends of messages; this causes confusion too (see [`printf()` anomaly after `fork()`](https://stackoverflow.com/questions/2530663/printf-anomaly-after-fork/)). – Jonathan Leffler May 24 '16 at 22:26
  • 1
    Agreed - I see nothing wrong with the output of this program. Async is async. If you want 123123 across processes, you either shouldn't use `fork`, or you are going to have to work a bit harder on synchronizing things. – Michael Dorgan May 24 '16 at 22:33
  • I am supposed to launch three child processes from one parent process. Since we only learned about forks I thought this is the way to go. We can use `environ, strol, fork, waitpid, usleep, fflush` (but everything but fork is new to me). I thought the processes are running at the same time and the scheduler tells the processes which process can go first. which will create kind of "random" number combinations from 0 to 2 (I switched up the numers sry). To get a one line result and not 60 line result I didn't use newlines. – Rasalas May 24 '16 at 22:37
  • 1
    The parent process calls `fork`, then `wait`, then `wait`, then `wait`, then `fork`, then `wait`, then `wait`, then `wait`, then `fork`, then `wait`, then `wait`, then `wait`. It's not surprising that when the parent process calls `wait`, it waits. – user253751 May 24 '16 at 22:38
  • @immibis thanks - but this isn't the problem, I think. The task says that the process should wait 1ms for every loop. – Rasalas May 24 '16 at 22:43
  • 2
    @Rasalas Why do you think that is not the problem? – user253751 May 24 '16 at 22:45
  • @immibis well I read the 2 answers and now I kind of get what you are talking about - sry... I thought that the wait is supposed to be there since the process should wait for 1ms for every loop. – Rasalas May 24 '16 at 22:48
  • 1
    Don't get into the habit of calling `exit` from your child processes. This can lead to serious errors and has, in the past, been the cause of bugs with major security implications. Use `_exit` in every process but one. – David Schwartz May 24 '16 at 22:49

2 Answers2

3

Moderately workable code:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

static void printfXtimes(int a, int b)
{
    for (int i = 0; i < b; i++)
    {
        printf("%i\n", a);
        usleep(10000);
        //sleep(1);
    }
}

int main(void)
{
    for (int kid = 0; kid < 3; ++kid)
    {
        int pid = fork();
        if (pid < 0)
        {
            exit(EXIT_FAILURE);
        }
        else if (pid > 0)
        {
            /* Parent process */
            printf("PID %d ready\n", pid);
        }
        else
        {
            /* Child process */
            printfXtimes(kid, 10);
            exit(EXIT_SUCCESS);
        }
    }

    for (int kid = 0; kid < 3; ++kid)
    {
        int status;
        int corpse = wait(&status);
        printf("PID %d exited 0x%.4X\n", corpse, status);
    }
}

Notes:

  • When using fork(), the correct return type for main() is int, not void. You can use void main() on Windows; everywhere else, it is wrong (almost everywhere else — specific systems could document it as OK, like Windows does). See What should main() return in C and C++?
  • One problem is that after you launch each child, you wait for three children to die. That loop should be after the launch loop. Otherwise, you're forcing sequential processing, not asynchronous processing.
  • Another problem is that you don't use newlines at the ends of messages; this causes confusion too (see printf() anomaly after fork()).

Example output (no piping):

PID 34795 ready
PID 34796 ready
0
1
2
PID 34797 ready
0
1
2
0
1
2
0
1
2
0
1
2
0
1
2
1
2
0
1
0
2
1
0
2
1
2
0
PID 34795 exited 0x0000
PID 34797 exited 0x0000
PID 34796 exited 0x0000

Example output (piped to sed):

0
0
0
0
0
0
0
0
0
0
PID 34789 ready
1
1
1
1
1
1
1
1
1
1
PID 34789 ready
PID 34790 ready
2
2
2
2
2
2
2
2
2
2
PID 34789 ready
PID 34790 ready
PID 34791 ready
PID 34789 exited 0x0000
PID 34791 exited 0x0000
PID 34790 exited 0x0000

If you've read and understood the "printf() anomaly after fork()" question, you should understand about line buffering and full buffering, and the output via sed should be explicable (in particular, why there are extra copies of the PID nnnnn ready messages).

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

Just missplaced { and } I think and missing flush. Not compile-tested:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

void printfXtimes(int a, int b)
{
    int i;
    for(i=0;i<b;i++) {
        printf("%i",a);
        fflush(stdout);
        sleep(1);
    }
}

int main(int argc, char *argv[]){
    for(int kid = 0; kid < 3; ++kid) {
        int pid = fork();
        if(pid < 0){
            exit(EXIT_FAILURE);
        }else if (pid > 0){
            /* Parent process */
            printf("ready");
        }else{
            /* Child process */
            printfXtimes(kid,20);
            exit(EXIT_SUCCESS);
        }
    }
    for (int kid = 0; kid < 3; ++kid) {
        int status;
        pid_t pid = wait(&status);
    }
    return  0;
}
Stian Skjelstad
  • 2,277
  • 1
  • 9
  • 19