Difference between revisions of "Fork system call"

From Teknologisk videncenter
Jump to: navigation, search
m
m (What is fork)
 
(11 intermediate revisions by the same user not shown)
Line 1: Line 1:
*Example of creating a Linux [[Daemon linux|daemon]] process
+
{{TOCright}}
=check=
+
'''fork()''' is one of several functions to "spawn" a process
 +
=Use of fork=
 +
==Magic or Qbit?==
 +
<source lang=c line>
 +
#include <stdio.h>
 +
#include <sys/types.h>
 +
#include <unistd.h>
 +
 
 +
int main(void) {
 +
        if (fork()) {
 +
                printf("True\n");
 +
        } else {
 +
                printf("False\n");
 +
        }
 +
        return(0);
 +
}
 +
</source>
 +
When running the above code:
 +
<source lang=bash>
 +
heth@emb3:~/bin/$ gcc process0.c -o process0
 +
heth@emb3:~/bin/$ ./process0
 +
True
 +
False
 +
</source>
 +
 
 +
==What is fork==
 +
[[Fork system call|fork()]] creates a new process by duplicating the calling process.  The new process is referred to as the child process.  The calling process is referred to as the parent process.
 +
*PID - Process ID - the ID of a running process
 +
*PPID - Parent Process ID - default the ID of the process that created this process or 1 if the parent died.
 +
 
 +
<source lang=c line>
 +
#include <stdio.h>
 +
#include <sys/types.h>
 +
#include <unistd.h>
 +
 
 +
int main(void) {
 +
        int pid;
 +
 
 +
        printf("Parent: PPID is %d and PID is %d\n", getppid(), getpid() );
 +
 
 +
        if ((pid=fork()) > 0) {
 +
                printf("Parent: PPID is %d and PID is %d\n", getppid(), getpid() );
 +
                printf("Parent: I got a child with PID %d\n", pid);
 +
        } else {
 +
                printf("Child.: My parent is PPID %d and my PID is %d\n", getppid(), getpid() );
 +
        }
 +
        return(0);
 +
}
 +
</source>
 +
When running this code - different results can occur:
 
<source lang=bash>
 
<source lang=bash>
heth@emb3:~/bin/htiot$ ps xo pid,ppid,pgid,sid,comm | grep -P '(screen|PPID)'
+
heth@emb3:~/bin/$ gcc process1.c -o process1
    PID   PPID    PGID    SID COMMAND
+
heth@emb3:~/bin/$ ./process1
  500011      1 500011  500011 screen
+
Parent: PPID is 3480753 and PID is 3490474
 +
Parent: PPID is 3480753 and PID is 3490474
 +
Child.: My parent is PPID 3490474 and my PID is 3490475
 +
Parent: I got a child with PID 3490475
 +
heth@emb3:~/bin$ ./process1
 +
Parent: PPID is 3480753 and PID is 3490481
 +
Parent: PPID is 3480753 and PID is 3490481
 +
Parent: I got a child with PID 3490482
 +
Child.: My parent is PPID 3490481 and my PID is 3490482
 +
</source>
 +
 
 +
==Example of creating a daemon in Linux==
 +
{{:Daemon linux}}
 +
 
 +
=Example of creating several processes=
 +
See same example in [[Bash processes#example|bash]]
 +
<source lang=c line>
 +
#include <stdio.h>
 +
#include <sys/types.h>
 +
#include <unistd.h>
 +
#include <wait.h>
 +
 
 +
void childprocess(char *name, int count_to) {
 +
        int counter = 0;
 +
 
 +
        printf("My name is %s and my PID is %d\n", name, getpid());
 +
 
 +
        while (counter < count_to) {
 +
                sleep(1);
 +
                counter = counter +1;
 +
                printf("%s counted to %i\n", name, counter);
 +
        }
 +
        printf("%s signing off\n", name);
 +
}
 +
 
 +
 
 +
int main(void) {
 +
        int wstatus; // Used by c wait function
 +
 
 +
        printf("I am the main function and my PID is %i\n", getpid());
 +
 
 +
        if (fork() == 0) { // fork returns 0 for child
 +
                childprocess("Hans", 5);
 +
                return(0);      // Child process finished
 +
        }
 +
 
 +
        if (fork() == 0) {
 +
                childprocess("Ulla", 3);
 +
                return(0);
 +
        }
 +
 
 +
        while(wait(&wstatus) > 0);
 +
        printf("Main signing off\n");
 +
        return(0);
 +
}
 +
 
 +
</source>
 +
=Parent and child with different code=
 +
<onlyinclude>
 +
If we want a parent and a child to execute different code and share a resource, for example a server that send information to a client. 
 +
 
 +
Three files:
 +
# '''my_system.c''' - forks and starts the server code as parent and the client code as child.
 +
# '''server.c"' - contains the server code
 +
# '''client.c''' - contains the client code
 +
==Typical output when starting my_system==
 +
'''Note:'''  
 +
* Server executable running with the parent PID
 +
* Client executable running with the child PID
 +
<source lang=text>
 +
Starting server as parent - my PID is 2644553
 +
Starting client as child  - my PID is 2644554
 +
Server started my PID is 2644553
 +
Client started my PID is 2644554
 +
Client received: hello: 1
 +
Client received: hello: 2
 +
Client received: hello: 3
 +
Client received: hello: 4
 +
Client received: hello: 5
 +
Server signing out
 +
Client signing out
 +
</source>
 +
 
 +
==my_system.c==
 +
<source lang=c line>
 +
#include <stdio.h>
 +
#include <unistd.h>
 +
#include <sys/types.h>
 +
 
 +
int main()
 +
{
 +
        int arr[2];
 +
        char argv[50];
 +
        pipe(arr);
 +
        if(fork())
 +
        {
 +
                printf("Starting server as parent - my PID is %d\n", getpid());
 +
                fflush(stdout);
 +
                close(arr[0]);
 +
                sprintf(argv,"%d",arr[1]);
 +
                execlp("./server","server",argv,NULL);
 +
        }
 +
        else
 +
        {
 +
                printf("Starting client as child - my PID is %d\n", getpid());
 +
                fflush(stdout);
 +
                close(arr[1]);
 +
                sprintf(argv,"%d",arr[0]);
 +
                execlp("./client","client",argv,NULL);
 +
        }
 +
        return 1;
 +
}
 +
</source>
 +
 
 +
==server.c==
 +
<source lang=c line>
 +
#include <stdio.h>
 +
#include <sys/types.h>
 +
#include <unistd.h>
 +
#include <stdlib.h>
 +
#include <string.h>
 +
 
 +
int main(int argc,char *argv[])
 +
{
 +
        char buf[40]="hello";
 +
        int fd,i;
 +
 
 +
        fd = atoi(argv[1]);
 +
        printf("Server started my PID is %d\n", getpid());
 +
        for (i=1; i <= 5; i++) {
 +
                sprintf(buf,"hello: %d",i);
 +
                write(fd,buf,strlen(buf)+1);
 +
                sleep(1);
 +
        }
 +
        buf[0] == 0;
 +
        close(fd);
 +
        puts("Server signing out");
 +
 
 +
        return 0;
 +
}
 +
</source>
 +
==client.c==
 +
<source lang=c line>
 +
#include <stdio.h>
 +
#include <unistd.h>
 +
#include <sys/types.h>
 +
#include <stdlib.h>
 +
 
 +
int main(int argc,char *argv[])
 +
{
 +
        char buf[11];
 +
        int fd;
 +
 
 +
        printf("Client started my PID is %d\n", getpid());
 +
        fd = atoi(argv[1]);
 +
        while(read(fd,buf,10) > 0)
 +
        {
 +
                printf("Client received: %s\n",buf);
 +
        }
 +
        close(fd);
 +
        printf("Client signing out\n");
 +
        return 0;
 +
}
 +
 
 
</source>
 
</source>
 +
</onlyinclude>
  
 
=Links=  
 
=Links=  
 
*[https://devarea.com/linux-fork-system-call-and-its-pitfalls/#.Y5v3THbMJPY good article from devarea.com]
 
*[https://devarea.com/linux-fork-system-call-and-its-pitfalls/#.Y5v3THbMJPY good article from devarea.com]
[[Category:Linux]]
+
[[Category:Linux]][[Category:C]]

Latest revision as of 06:36, 19 December 2022

fork() is one of several functions to "spawn" a process

Use of fork

Magic or Qbit?

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <unistd.h>
 4 
 5 int main(void) {
 6         if (fork()) {
 7                 printf("True\n");
 8         } else {
 9                 printf("False\n");
10         }
11         return(0);
12 }

When running the above code:

heth@emb3:~/bin/$ gcc process0.c -o process0
heth@emb3:~/bin/$ ./process0
True
False

What is fork

fork() creates a new process by duplicating the calling process. The new process is referred to as the child process. The calling process is referred to as the parent process.

  • PID - Process ID - the ID of a running process
  • PPID - Parent Process ID - default the ID of the process that created this process or 1 if the parent died.
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <unistd.h>
 4 
 5 int main(void) {
 6         int pid;
 7 
 8         printf("Parent: PPID is %d and PID is %d\n", getppid(), getpid() );
 9 
10         if ((pid=fork()) > 0) {
11                 printf("Parent: PPID is %d and PID is %d\n", getppid(), getpid() );
12                 printf("Parent: I got a child with PID %d\n", pid);
13         } else {
14                 printf("Child.: My parent is PPID %d and my PID is %d\n", getppid(), getpid() );
15         }
16         return(0);
17 }

When running this code - different results can occur:

heth@emb3:~/bin/$ gcc process1.c -o process1
heth@emb3:~/bin/$ ./process1
Parent: PPID is 3480753 and PID is 3490474
Parent: PPID is 3480753 and PID is 3490474
Child.: My parent is PPID 3490474 and my PID is 3490475
Parent: I got a child with PID 3490475
heth@emb3:~/bin$ ./process1
Parent: PPID is 3480753 and PID is 3490481
Parent: PPID is 3480753 and PID is 3490481
Parent: I got a child with PID 3490482
Child.: My parent is PPID 3490481 and my PID is 3490482

Example of creating a daemon in Linux

Example of creating a daemon in Linux: (See systemd debian for systemd daemons)

  • setsid() - damon will be the session leader. Sets Session ID (SID) and Group ID (GID) to Process ID (PID)
  • Reopening stdin, stdout and stderr to /dev/null detaches the process from the controlling terminal and Parent PID is set to 1 (init or systemd - depending on Linux version/distribution)
 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <stdlib.h>
 4 #include <syslog.h>
 5 void  daemon_create(void);
 6 
 7 int main(void) {
 8         printf("Starting my_daemon\n");
 9         openlog("my_daemon", LOG_INFO, LOG_DAEMON);
10         daemon_create();
11         for (int i=0; i < 100; i++) {
12                 syslog(LOG_INFO,"Countet to %d", i);
13                 sleep(2);
14         }
15         return(0);
16 }
17 
18 void  daemon_create(void) {
19     pid_t pid;
20 
21     pid = fork();
22     if(pid < 0){
23         syslog(LOG_ERR, "Error in fork: %m");
24         exit(1);
25     }
26     if(pid > 0) {
27         syslog(LOG_INFO, "Parent dying");
28         exit(0); // Parent die
29     }
30     if(setsid() < 0){ // Make child session leader
31         syslog(LOG_ERR, "Error in setsid: %m");
32         exit(2);
33         }
34         if (freopen("/dev/null", "r", stdin) == NULL
35         || freopen("/dev/null", "w", stdout) == NULL
36         || freopen("/dev/null", "w", stderr) == NULL ) {
37                 syslog(LOG_ERR, "When creating daemon freopen from STDIN/OUT/ERR failed: %m");
38                 exit(3);
39    }
40 }

Checking the daemon

  • Daemon detached from TTY - PPID is 1
  • Session and session group leader - SID and PGID same as PID
$ ps xo uname,pid,ppid,pgid,sid,tty,comm | grep -P '(my_daemon|COMMAND)'
USER         PID    PPID    PGID     SID TTY       COMMAND
heth      778254       1  778254  778254 ?        my_daemon
$ tail -f /var/log/sysg
Dec 20 12:37:59 emb3 my_daemon: Countet to 2
Dec 20 12:38:01 emb3 my_daemon: Countet to 3
Dec 20 12:38:03 emb3 my_daemon: Countet to 4
Dec 20 12:38:05 emb3 my_daemon: Countet to 5
...


Example of creating several processes

See same example in bash

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <unistd.h>
 4 #include <wait.h>
 5 
 6 void childprocess(char *name, int count_to) {
 7         int counter = 0;
 8 
 9         printf("My name is %s and my PID is %d\n", name, getpid());
10 
11         while (counter < count_to) {
12                 sleep(1);
13                 counter = counter +1;
14                 printf("%s counted to %i\n", name, counter);
15         }
16         printf("%s signing off\n", name);
17 }
18 
19 
20 int main(void) {
21         int wstatus; // Used by c wait function
22 
23         printf("I am the main function and my PID is %i\n", getpid());
24 
25         if (fork() == 0) { // fork returns 0 for child
26                 childprocess("Hans", 5);
27                 return(0);      // Child process finished
28         }
29 
30         if (fork() == 0) {
31                 childprocess("Ulla", 3);
32                 return(0);
33         }
34 
35         while(wait(&wstatus) > 0);
36         printf("Main signing off\n");
37         return(0);
38 }

Parent and child with different code

If we want a parent and a child to execute different code and share a resource, for example a server that send information to a client.

Three files:

  1. my_system.c - forks and starts the server code as parent and the client code as child.
  2. server.c"' - contains the server code
  3. client.c - contains the client code

Typical output when starting my_system

Note:

  • Server executable running with the parent PID
  • Client executable running with the child PID
Starting server as parent - my PID is 2644553
Starting client as child  - my PID is 2644554
Server started my PID is 2644553
Client started my PID is 2644554
Client received: hello: 1
Client received: hello: 2
Client received: hello: 3
Client received: hello: 4
Client received: hello: 5
Server signing out
Client signing out

my_system.c

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <sys/types.h>
 4 
 5 int main()
 6 {
 7         int arr[2];
 8         char argv[50];
 9         pipe(arr);
10         if(fork())
11         {
12                 printf("Starting server as parent - my PID is %d\n", getpid());
13                 fflush(stdout);
14                 close(arr[0]);
15                 sprintf(argv,"%d",arr[1]);
16                 execlp("./server","server",argv,NULL);
17         }
18         else
19         {
20                 printf("Starting client as child  - my PID is %d\n", getpid());
21                 fflush(stdout);
22                 close(arr[1]);
23                 sprintf(argv,"%d",arr[0]);
24                 execlp("./client","client",argv,NULL);
25         }
26         return 1;
27 }

server.c

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <unistd.h>
 4 #include <stdlib.h>
 5 #include <string.h>
 6 
 7 int main(int argc,char *argv[])
 8 {
 9         char buf[40]="hello";
10         int fd,i;
11 
12         fd = atoi(argv[1]);
13         printf("Server started my PID is %d\n", getpid());
14         for (i=1; i <= 5; i++) {
15                 sprintf(buf,"hello: %d",i);
16                 write(fd,buf,strlen(buf)+1);
17                 sleep(1);
18         }
19         buf[0] == 0;
20         close(fd);
21         puts("Server signing out");
22 
23         return 0;
24 }

client.c

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <sys/types.h>
 4 #include <stdlib.h>
 5 
 6 int main(int argc,char *argv[])
 7 {
 8         char buf[11];
 9         int fd;
10 
11         printf("Client started my PID is %d\n", getpid());
12         fd = atoi(argv[1]);
13         while(read(fd,buf,10) > 0)
14         {
15                 printf("Client received: %s\n",buf);
16         }
17         close(fd);
18         printf("Client signing out\n");
19         return 0;
20 }


Links