How can i create 5 Processes using fork()? - c

I want to create 5 processes just like the picture shown i have tried a lil bit by printing out their pid's but its hard for me to visualize the fork() creating them and get exactly what I want [The image shows 5 processes connected by pipes]
P
/ \
M M
| |
C C

When you use fork() the kernel will create one new process and will return to the child (the new process) 0 and the PID to the parent. So, knowing this this is the following code to create the tree
if ((pid = fork()) == 0) {
//I am process M1
if (pid = form()) == 0) {
//I am process C1
}
} else {
// I am still in P, so go on the next branch
if ((pid = fork()) == 0) {
//I am process M2
if (pid = form()) == 0) {
//I am process C2
}
}
}
Use ps --forest to visualize the process tree as in following example
~# ps --forest
PID TTY TIME CMD
1295 pts/0 00:00:00 sudo
1296 pts/0 00:00:00 \_ su
1297 pts/0 00:00:01 \_ bash
3541 pts/0 00:00:00 \_ ps
So you will see something like:
~# ps --forest
PID TTY TIME CMD
1295 pts/0 00:00:00 a.out
1296 pts/0 00:00:00 \_ a.out
1297 pts/0 00:00:00 \_ a.out
1298 pts/0 00:00:00 \_ a.out
1299 pts/0 00:00:00 \_ a.out
Which will tell you if you have successfully made the tree.

Related

Child process should not die with parent process

The following scenario:
process_1.bin starts doSomeThing.sh
doSomeThing.sh should kill process_1.bin first but keep running itself and do some other things
I have tried fork, exec, screen, p_threads, daemon, and some without success.
Every time the doSomeThing.sh starts and kills the process_1.bin, it kills itself because the parent process is killed.
doSomeThing.sh tells me: "leaving program after kill signal!"
Unfortunately, this does not work either:
pid_t pid;
pid = fork();
if (pid < 0)
exit(EXIT_FAILURE);
if (pid > 0) // Success: Let the parent terminate
exit(EXIT_SUCCESS);
if (setsid() < 0)
exit(EXIT_FAILURE);
pid = fork();
if (pid < 0)
exit(EXIT_FAILURE);
if (pid > 0)
exit(EXIT_SUCCESS);
// umask(0);
// chdir("/");
switch(pid)
{
case -1: // Fork() has failed
perror ("fork");
break;
case 0: // This is processed by the child
// deamon(0,0);
system("/root/doSomeThing.sh");
// system("screen -dmS doSomeThing /root/doSomething.sh")
// char *name[] = {
// "/bin/bash",
// "-c",
// "/root/doSomeThing.sh",
// NULL
// };
// if(execvp(name[0], name) < 0)
// perror("execvp");
exit(0);
break;
default: // This is processed by the parrent
break;
}
How can I direct the doSomeThing.sh to kill the process_1.bin but still stay alive itself?
Apart from ignoring SIGTERM as suggested by Jonathan Leffler, you could make the child process a daemon so that its life will become independant of the life of its parent. Linux has a command to start a process as a daemon daemonize or a library function for a program willing to detach from its parent and its controlling terminal daemon.
Your child process should not be dying. Here's a pair of shell scripts simulating what you describe.
process1.bin
#!/bin/sh
echo "$0: at work"
trap 'echo "$0: Death threat received"; exit 1' 1 2 3 13 15
sh doSomething.sh &
echo "$0: so far, so good"
wait
echo "$0: it's sad when all your children die"
ps -f
echo "$0: exiting normally"
exit 0
doSomething.sh
#!/bin/sh
#
# Commit parenticide and continue, preferably without dying.
#PPID=$(ps -fp$$ | colnum -c 3)
echo "Before"
ps -f
(
set -x
kill $PPID
)
sleep 1
echo ""
echo "After"
ps -f
sleep 5
echo "$0: Goodbye, Cruel World!"
One time when I ran it, I got the output:
$ ./process1.bin
./process1.bin: at work
./process1.bin: so far, so good
Before
UID PID PPID C STIME TTY TIME CMD
501 649 641 0 9:58AM ttys000 0:00.14 -bash
501 29760 649 0 8:47AM ttys000 0:00.01 sh
501 29793 29760 0 8:47AM ttys000 0:00.01 /bin/sh ./process1.bin
501 29794 29793 0 8:47AM ttys000 0:00.01 sh doSomething.sh
501 661 657 0 9:58AM ttys001 0:00.05 -bash
501 693 688 0 9:58AM ttys002 0:00.05 -bash
501 738 731 0 9:58AM ttys007 0:00.31 -bash
501 769 766 0 9:58AM ttys008 0:00.05 -bash
501 848 847 0 9:58AM ttys009 0:00.05 -bash
501 884 881 0 9:58AM ttys010 0:00.12 -bash
501 946 920 0 9:58AM ttys011 0:00.15 -bash
+ kill 29793
./process1.bin: Death threat received
$
After
UID PID PPID C STIME TTY TIME CMD
501 649 641 0 9:58AM ttys000 0:00.14 -bash
501 29760 649 0 8:47AM ttys000 0:00.01 sh
501 29794 1 0 8:47AM ttys000 0:00.01 sh doSomething.sh
501 661 657 0 9:58AM ttys001 0:00.05 -bash
501 693 688 0 9:58AM ttys002 0:00.05 -bash
501 738 731 0 9:58AM ttys007 0:00.31 -bash
501 769 766 0 9:58AM ttys008 0:00.05 -bash
501 848 847 0 9:58AM ttys009 0:00.05 -bash
501 884 881 0 9:58AM ttys010 0:00.12 -bash
501 946 920 0 9:58AM ttys011 0:00.15 -bash
doSomething.sh: Goodbye, Cruel World!
$
Note that my $ prompt appears after 'Death threat received'. The following output is from doSomething; I hit return after 'Goodbye, Cruel World!' to get the final $ prompt.
Testing with Bash on a MacBook Pro running macOS Catalina 10.15.7.
In a comment, oemer_1907 says:
The shell script kills all processes to play the update (including the C update process). Once the C update process is killed by the shell update process, it sends a SIGTERM to all its children. Hence, the shell script is also killed. If instead it just calculates without killing its parent, then it just keeps running until the end.
Well, if the parent process sends SIGTERM to all its children, your child script, doSomething.sh, must ignore the SIGTERM signal using either of these:
trap "" 15
trap "" TERM
before it sends a signal to its parent. Or the parent process could arrange not to send the signal to this child. Or it could arrange for the child to ignore SIGTERM before it is executed:
signal(SIGTERM, SIG_IGN);
…exec child…
Or …

Problem running ps to find PID with multiple users

When I run the following code and then run ps to see the processes running, I only get 4 ./a.out running processes even though there are 5 forks. Why is that? How am I able to see the other fork? Also, if multiple people are using my computer, running the same process a.out, how can I terminate only my processes, using only linux commands? Please help.
PID TTY TIME CMD
32941 ttys000 0:00.10 -bash
34098 ttys000 0:00.08 less
33651 ttys000 0:00.00 ./a.out
33652 ttys000 0:00.00 ./a.out
33654 ttys000 0:00.00 ./a.out
33655 ttys000 0:00.00 ./a.out
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#define N 5 /* How many children to make. */
#define D 1200 /* Sleep 1200 seconds = 20 minutes */
int main(void)
{
int i;
pid_t p;
for (i = 0; i < N; i++) {
p = fork();
if (p == 0) {
close(0);
close(1);
close(2);
if (i == 2) {
setsid();
}
sleep(D);
return 0;
}
}
return 0;
}
All five processes are running, but you're using the ps command that only shows processes associated with your session, but the setsid() called for i=2 sets a different session, so the default ps options won't show you.
$ ps
PID TTY TIME CMD
3048 pts/0 00:00:00 bash
8288 pts/0 00:00:00 a.out
8289 pts/0 00:00:00 a.out
8291 pts/0 00:00:00 a.out
8292 pts/0 00:00:00 a.out
8301 pts/0 00:00:00 ps
$ ps -fe | grep a.out
steve 8288 1 0 13:39 pts/0 00:00:00 ./a.out
steve 8289 1 0 13:39 pts/0 00:00:00 ./a.out
steve 8290 1 0 13:39 ? 00:00:00 ./a.out <-- missing one
steve 8291 1 0 13:39 pts/0 00:00:00 ./a.out
steve 8292 1 0 13:39 pts/0 00:00:00 ./a.out
steve 8303 3048 0 13:40 pts/0 00:00:00 grep --color=auto a.out
$
By default, ps only displays processes with the same session id as itself and associated with a terminal. When you changed the session id of one of the processes, you disqualified it from being listed. ps x will include all of your processes.
By default, ps only lists the processes belong to you. You can be sure of this by using ps ux to include the owners of the processes in the output.
You can use the kill utility to kill these processes. Unless you are root, you can't kill other processes owned by others even if you tried.

How assign a new terminal window to each child process

I want to fork multiple processes and assign each child process it's own terminal window so that IPC can be demonstrated easily.
Forking goes on fine, and if I run the child processes on the same terminal it runs fine.
However to make each child process have its own terminal window, I do
execl("/usr/bin/xterm", "xterm", "-e", "yourprogram", NULL);
The program runs in a new window, but its PID is different from that shown by the parent which forks the process. What am I doing wrong?
Thanks
edit1 - this is my main function (the parent process). I fork 4 child processes. I want each child process to have its own terminal window. However the child process just exits, and a new process with a different PID continues to run in the new terminal.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
pid_t pid[4];
int i = 0;
int status;
//Fork four new processes
for(i=0; i<4; i++)
{
pid[i] = fork();
if(pid[i] == 0 && i == 0)
{
execl("/usr/bin/xterm", "xterm", "./child1", NULL);
exit(1);
}
else if(pid[i] == 0 && i == 1)
{
execl("/usr/bin/xterm", "xterm", "./child2", NULL);
exit(1);
}
else if(pid[i] == 0 && i == 2)
{
execl("/usr/bin/xterm", "xterm", "./child3", NULL);
exit(1);
}
else if(pid[i] == 0 && i == 3)
{
execl("/usr/bin/xterm", "xterm", "./child4", NULL);
exit(1);
}
else
{
//Parent process
printf("The main function has forked a process with pid: %d\n", pid[i]);
}
}
for(i=0;i<4;i++)
{
status = waitpid(pid[i], NULL, 0);
if(status == pid[i])
printf("%d: Process Terminated Successfully\n", pid[i]);
else
{
perror("waitpid");
exit(1);
}
}
return 1;
}
edit2 - added ps -u output:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
dell-pc 3024 0.1 0.0 26872 5480 pts/0 Ss 16:54 0:00 bash
dell-pc 3038 0.0 0.0 4200 632 pts/0 S+ 16:54 0:00 ./main
dell-pc 3039 22.5 0.1 109240 11116 pts/0 S+ 16:54 0:01 xterm ./child1
dell-pc 3040 26.1 0.1 109240 11268 pts/0 R+ 16:54 0:02 xterm ./child2
dell-pc 3041 28.7 0.1 109240 11180 pts/0 S+ 16:54 0:02 xterm ./child3
dell-pc 3042 27.0 0.1 109240 11288 pts/0 S+ 16:54 0:02 xterm ./child4
dell-pc 3044 4.1 0.0 4200 648 pts/24 Ss+ 16:55 0:00 child3
dell-pc 3046 3.7 0.0 4200 680 pts/26 Ss+ 16:55 0:00 child4
dell-pc 3048 3.8 0.0 4200 792 pts/25 Ss+ 16:55 0:00 child2
dell-pc 3050 3.3 0.0 4200 660 pts/14 Ss+ 16:55 0:00 child1
dell-pc 3060 2.0 0.0 26816 5412 pts/27 Ss 16:55 0:00 bash
dell-pc 3072 0.0 0.0 22648 2688 pts/27 R+ 16:55 0:00 ps -u
edit3: added output of main:
The main function has forked a process with pid: 3491
The main function has forked a process with pid: 3492
The main function has forked a process with pid: 3493
The main function has forked a process with pid: 3494
3491: Process Terminated Successfully
3492: Process Terminated Successfully
3493: Process Terminated Successfully
3494: Process Terminated Successfully
I did a program like yours (naming it stackoverflow), executing vi in an xterm, and while it is running I open a third xterm to run ps -u. Output is:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
osboxes 1713 0.0 0.2 6588 4756 pts/0 Ss 18:56 0:00 bash
osboxes 1780 0.0 0.2 6508 4484 pts/1 Ss 19:12 0:00 bash
osboxes 1836 88.4 0.0 2020 532 pts/0 R+ 19:21 0:29 ./stackoverflow
osboxes 1837 0.1 0.4 12844 8952 pts/0 S+ 19:21 0:00 /usr/bin/xterm -e vi stackoverflow.txt
osboxes 1839 0.0 0.1 6072 3536 pts/2 Ss+ 19:21 0:00 vi stackoverflow.txt
osboxes 1840 0.0 0.1 4772 2452 pts/1 R+ 19:22 0:00 ps -u
Output of program is:
PID=1836
child PID=1837
So the child is still running xtermcommand. It created another child running vi (pid 1839).
IPC Demo and sample using terminal windows, under bash
Because it's easy under bash:
This will require simple terminal tools, like xterm. This was successfully tested with lxterm, mate-terminal, konsole and gnome-terminal. Of course, tmux and screen must be able too...
Ok, let's go. We assume you're already in some terminal window, we will name this initial console.
1. First opening a display window:
So, from the initial console, open log window:
exec 5> >(xterm -T 'Log window...' -e sh -c "cat /proc/$$/fd/5")
or
exec 5> >(xterm -e sh -c "printf '\\e];Log window...\\a';cat /proc/$$/fd/5")
exec 5> >(konsole --nofork -e sh -c "cat /proc/$$/fd/5")
exec 5> >(lxterm -T "Log window..." -e sh -c "cat /proc/$$/fd/5")
exec 5> >(mate-terminal -t 'Log window...' -x sh -c "cat /proc/$$/fd/5")
exec 5> >(gnome-terminal --window -x sh -c "printf '\\e];Log window...\\a';cat /proc/$$/fd/5")
Variant usefull for debugging
exec 5> >(xterm -e sh -c "printf '\\e];Log window...\\a';
tee </proc/$$/fd/5 /dev/tty | sed -u s/.*/now/|date -f -")
Will print date and time on each line output.
exec 5> >(xterm -e sh -c "printf '\\e];Log window...\\a';
tee </proc/$$/fd/5 /dev/tty | sed -u s/.*/now/|date -f - ; read foo")
Same, but will keep window open after closing from parent, waiting for terminal input (Return) before closing (or close by window manager).
2. Testing, then using this:
Always in initial console, hit:
echo >&5 This is a test string.
This must prompt in Log window.
Ok, now:
xterm -T 'Input window' -e bash --rcfile <(echo "exec 1>/proc/$$/fd/5") &
Note: There, double-quotes will ensure $$ will expand from initial window's shell level.
So now, you could enter command in Input window and read results on Log window.
3. Closing window
Window will close when file descriptor is closed:
exec 5>&-
Full script using 3 window
You may found full script there:
ipc_win-demo.sh.txt
ipc_win-demo.sh
For gnome terminal I used:
execl("/usr/bin/gnome-terminal", "gnome-terminal", "-q", "-e", "./my_binary", (char*)0);

Please explain the ps -aef response on RHEL

What does pts/2 indicate in the below output. Why there is no such for other dd processes?
$ ps -aef |grep dd
root 6553672 15073352 3 02:32:19 - 0:01 dd of=/dev/lv01 bs=1024k
padmin 9437410 16515110 1 02:43:32 **pts/2** 0:00 grep dd
root 13828156 11010220 0 02:32:33 - 0:00 dd of=/dev/lv02 bs=1024k
root 14155860 13828156 2 02:32:33 - 0:01 dd of=/dev/lv02 bs=1024k
root 15073352 13762812 0 02:32:19 - 0:00 dd of=/dev/lv01 bs=1024k
root 15532200 15925276 2 02:40:47 **pts/1** 0:03 dd of=/home/padmin/sample-dd-op bs=1024k
pts/X in the TTY column means that the process is connected to a pseudo terminal slave.
An empty value means:
The terminal session has ended
The command was fired by a daemon
This nice Answer shows the difference between PTS and TTY.

fork() and kill in linux

In my project, I need a sub-task to play in parallel with a parent task. I use fork() to create a parallel process which is aplay xyz.wav. Now when I want to kill the child process from the parent process e.g system("kill -9 aplay ") the aplay is killed, but I see two instances of the parent task. I think one of them is a copy made by the call to fork() and the other one is the original. And with each fork() call, the number of copies increases. I am conscious about memory overflow. I just want to keep the original process. I have tried to kill that parent copy but failed!copies of the parent process appear as 'defunct'.
the 'defucnt' process continue to increase as i call parallel process, whether i kill aplay or not. I also tried to kill defunt by its PID, it also didn't work.
static int
test(Core *pc, char *args)
{
pid1=fork();
if (pid1 ==0)
{
system ("ps " );
system("aplay /opt/Line_Tone_14s.wav");
_exit(0);
}
else if(pid1<0)
{
out("fork() ERROR (-1) returned\n");
}
else if(pid1>0)
{
out("I AM IN PARENT PROCESS() NOW\n");
}
return 1;
}
static int
test1(Core *pc, char *args)
{
system ("ps " );
system ("killall -9 aplay ");
return 1;
}
Initially
> PID TTY TIME CMD
1580 pts/0 00:00:00 sudo
1581 pts/0 00:00:00 su
1589 pts/0 00:00:00 bash
5732 pts/0 00:00:00 parent
5738 pts/0 00:00:00 sh
5739 pts/0 00:00:00 ps
>test
> PID TTY TIME CMD
1580 pts/0 00:00:00 sudo
1581 pts/0 00:00:00 su
1589 pts/0 00:00:00 bash
5732 pts/0 00:00:00 parent
5737 pts/0 00:00:00 parent
5740 pts/0 00:00:00 sh
5741 pts/0 00:00:00 aplay
5743 pts/0 00:00:00 sh
5744 pts/0 00:00:00 ps
>test1
>killed
after kill
>PID TTY TIME CMD
1580 pts/0 00:00:00 sudo
1581 pts/0 00:00:00 su
1589 pts/0 00:00:00 bash
5732 pts/0 00:00:00 parent
5737 pts/0 00:00:00 parent <defunct>
5753 pts/0 00:00:00 sh
5754 pts/0 00:00:00 ps
>test
> PID TTY TIME CMD
1580 pts/0 00:00:00 sudo
1581 pts/0 00:00:00 su
1589 pts/0 00:00:00 bash
5732 pts/0 00:00:00 parent
5737 pts/0 00:00:00 parent <defunct>
5759 pts/0 00:00:00 parent
5762 pts/0 00:00:00 sh
5763 pts/0 00:00:00 aplay
5765 pts/0 00:00:00 sh
5766 pts/0 00:00:00 ps
>test1
>killed
after kill
>PID TTY TIME CMD
1580 pts/0 00:00:00 sudo
1581 pts/0 00:00:00 su
1589 pts/0 00:00:00 bash
5732 pts/0 00:00:00 parent
5737 pts/0 00:00:00 parent <defunct>
5759 pts/0 00:00:00 parent <defunct>
5773 pts/0 00:00:00 sh
5774 pts/0 00:00:00 ps
i also tried with this in test() command
else if(pid1>0)
{
out("I AM IN PARENT PROCESS() NOW\n");
wait(&status);
}
by doing this only one parent process remain after aplay finishes to play sound, no matter how many times i call the "test" command. but the issue with this is that, I can not type any other command during sound play, until it finishes. so could not kill it in between playing the sound.
I want to play sound in parallel, and want to kill any time i want.
Don't kill it that way! You have the child PID in pid1, just use the kill() function to kill it.
Spawning an separate process to run killall is unnecessary, expensive and (as you've found out), not that reliable. What if there are five copies of that executable running?
You can use something like:
#include <sys/types.h>
#include <signal.h>
:
int rc = kill (pid1, 9); // or SIGKILL for portability, rather than 9.
// Check rc and errno.
in your parent.
I would also seriously look into removing the system calls in the child process as well since they start up separate processes. You can do better by using the exec family of calls the replace the program in the child's process space.

Resources