So I need to iterate fork() several times, creating child processes. The child processes are supposed to "do little or not processing" for example;
while(1)
sleep(1)
The parent is then supposed to gather the PID's of the children and kill them (harsh, I know!).
However they way I'm doing it at the minute executes the code in the "parent" block several times, but I only need it to execute once.
Here is an example; you need to store the pids in a table (here p[]).
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#define NSUB 10
int main ()
{
int i, n = NSUB, p[NSUB], q;
for (i = 0; i < n; i++) {
printf ("Creating subprocess %d ...\n", i);
p[i] = fork();
if (p[i] < 0) { perror ("fork"); exit (1); }
if (p[i] == 0) { /* subprocess */
printf ("Subprocess %d : PID %d\n", i, (int) getpid());
while (1) pause ();
exit (0);
}
}
sleep(2);
for (i = 0; i < n; i++) {
printf ("Killing subprocess %d ...\n", i);
if (kill (p[i], SIGTERM) < 0) perror ("kill");
}
for (i = 0; i < n; i++) {
printf ("waiting for a subprocess ...\n");
q = wait (NULL);
printf ("Subprocess terminated: PID %d\n", q);
}
exit (0);
}
Related
So, i have this piece of C code
I can't grasp what the second 'for' segment is about. When does it get terminated abnormally?
Can someone enlighten me on that?
#include<unistd.h>
#include<stdio.h>
#include <sys/wait.h>
#define N 30
int main() {
pid_t pid[N];
int i;
int child_status;
for (i = 0; i < N; i++) {
pid[i] = fork();
if (pid[i] == 0) {
sleep(60 - 2 * i);
exit(100 + i);
}
}
for (i = 0; i < N; i++) {
pid_t wpid = waitpid(pid[i], & child_status, 0);
if (WIFEXITED(child_status)) {
printf("Child%d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status));
} else {
printf("Child%d terminated abnormally\n", wpid);
}
}
return (0);
}
When child is terminate ,to be able to find with which value the child was terminated (either with exit or with return) i have to pash the second parametre in waitpid() with pointer to an integer.So in that integer on return from the call it will include 2 types of information
a) if child was terminated well with return or exit or stoped unexpectedly
b)the second type will be having the termination value.
If i want to know the information from (a) i need to use the macro WIFEXITED(), if this give me true the (b) emerged from macro WEXITSTATUS().This is a simple example
#include <stdio.h>
#include <stdlib.h> /* For exit() */
#include <unistd.h> /* For fork(), getpid() */
#include <sys/wait.h> /* For waitpid() */
void delay() { /* Just delay */
int i, sum=0;
for (i = 0; i < 10000000; i++)
sum += i;
printf("child (%d) exits...\n", getpid());
exit(5); /* Child exits with 5 */
}
int main() {
int pid, status;
pid = fork();
if (pid == 0) /* child */
delay();
printf("parent (%d) waits for child (%d)...\n", getpid(), pid);
waitpid(pid, &status, 0);
if (WIFEXITED(status)) /* Terminated OK? */
printf("child exited normally with value %d\n", WEXITSTATUS(status));
else
printf("child was terminated abnormaly.\n");
return 0;
}
SOS The macro WEXITSTATUS() return only the 8 least important bits of the value when the child is terminate.So if the child wants to "say" something to his parent through exit/waitpid it must be a number up to 255.
I am trying to fork() 10 child processes in one loop and then in another loop wait() for them to terminate and print their PID along with their exit status code. It cannot be done any other way or using any other function. Two loops/waves and the function wait();
This is what I have tried:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t wait_p, p[10], p_child;
int status;
for (int i = 0; i < 10; i++)
{
p[i] = fork();
}
for (int i = 0; i < 10; i++)
{
switch (p[i])
{
case 0:
p_child = getpid();
exit(p_child % 10);
break;
case -1:
puts("ERROR");
break;
default:
wait_p = wait(&status);
printf("Child with PID: %d", wait_p);
if (WIFEXITED(status))
printf(" terminated with STATUS: %d\n", WEXITSTATUS(status));
break;
}
}
return (EXIT_FAILURE);
}
This code will execute an endless count of child processes. It must print only the first original(issued by THE one parent) 10. What am I doing wrong?
You have to handle the child processes directly in your first loop:
for (int i = 0; i < 10; i++)
{
p[i] = fork();
if (p[i] == 0) {
p_child = getpid();
exit(p_child % 10);
} else if (p[i] == -1) {
perror("fork");
}
}
and then wait for them in the second loop
for (int i = 0; i < 10; i++)
{
wait_p = wait(&status);
printf("Child with PID: %d", wait_p);
if (WIFEXITED(status))
printf(" terminated with STATUS: %d\n", WEXITSTATUS(status));
}
You cannot handle the case, that fork() returns in the child process (yielding 0 as return value), in your second loop, otherwise each child process in the first loop keeps forking more child processes.
I got an integer matrix in shared memory with n colums, so I create n processes, each of them make the sum of a colum. The problem is that they don't execute in parallel. There is the code (this doesn't actually do the sum, was to test):
int pid2[n];
i=0;
do{
pid2[i] = fork();
if(pid2[i]==-1) printf("fork() fail!\n");
else if(pid2[i]==0){
printf("Start process %d \n", i);
sleep((rand() % 50)/10);
printf("Process %d terminated" ,i);
}
else i++;
}
while(i<n&&pid2[i]>0);
What I get is that it runs in this order process 3, 2, 1 and ends in the same order, always. But the sleep is random, so the arrival time should be random too! Also I don't understand why it starts from process 3.
Your code is wrong and don't do what you think.
In the case of fork() success, the caller increments i, and then the final test of the while is false, so the original process terminates. While the new process executes its code "start 0", "terminates 0", then jumps to the test which is true and then fork again, etc. So your processes are always produced one after the other in the same order.
Here is the corrected code (with random seeding):
int pid2[n];
i=0;
do{
pid2[i] = fork();
if(pid2[i]==-1) printf("fork() fail!\n");
else if(pid2[i]==0){
printf("Start process %d \n", i);
sleep((rand() % 50)/10);
printf("Process %d terminated" ,i);
exit(0); // ends the child
}
else i++;
}
while(i<n&&pid2[i-1]>0); // test is last pid is correct
When you don't seed random number generator with srandom function, you'll always get the same sequence of "random" numbers. Usually you seed it doing srandom(time(NULL)) call.
Check this simple program:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf("%d\n", rand());
return 0;
}
On my computer it always outputs 1804289383.
Also, when you call rand in your child process it always inherits parent's state of random-number-generating-machine, so your children will always generate the same random number. You shall generate this random number before forking. In the following code all children return the same random value:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#define CHILDREN 3
int main(void) {
int i;
for (i = 0; i < CHILDREN; ++i) {
if (fork() == 0) {
printf("rand is %d in child %d\n", rand(), i);
return 0;
}
wait(NULL);
}
return 0;
}
Last thing is, creating some processes one-after-another doesn't mean they will get processor's time in that order. It's perfectly OK that when you fork your first child, processor's context will return to the parent, who will do another fork, and then processor's context will be assigned to the second child, not the first one.
Code that works:
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#define CHILDREN 3
int main(void) {
int pid, i, children = 0;
srand(time(NULL));
double sleeptime;
for (i = 0; i < CHILDREN; ++i) {
sleeptime = (rand() % 50) / 10.0;
pid = fork();
if (pid == -1) {
perror("fork failed");
} else if (pid == 0) {
printf("Child %d crated\n", i);
fflush(stdout);
sleep(sleeptime);
printf("Child %d terminated\n", i);
fflush(stdout);
return 0;
} else {
++children;
}
}
// wait for all childredn
for (i = 0; i < children; ++i) {
wait(NULL);
}
return 0;
}
So here is my code that will take an int as an command line argument then fork N child processes (That run simultaneously). And then when each child ends, the parent will echo the child that child exit status.
But right now I can only do child by child but not simultaneously. How can I do it?
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
int main ( int argc, char *argv[] )
{
int i, pid, ran;
for(i = 0; i < atoi(argv[1]); i++) {
pid = fork();
srand(time(NULL));
ran = (rand() % 10) + 1 ;
if (pid < 0) {
printf("Error");
exit(1);
} else if (pid == 0) {
printf("Child (%d): %d\n", i + 1, getpid());
printf("Sleep for = %d\n", ran);
sleep(ran);
exit(ran);
} else {
int status = 0;
pid_t childpid = wait(&status);
printf("Parent knows child %d is finished. \n", (int)childpid);
}
}
}
You're calling wait() inside of the loop where you're spawning the children, so it won't continue the loop to start the next child until the current one is done.
You need to call wait() outside of the loop in a separate loop:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
int main ( int argc, char *argv[] )
{
int i, pid, ran;
for(i = 0; i < atoi(argv[1]); i++) {
pid = fork();
srand(time(NULL));
ran = (rand() % 10) + 1 ;
if (pid < 0) {
printf("Error");
exit(1);
} else if (pid == 0) {
printf("Child (%d): %d\n", i + 1, getpid());
printf("Sleep for = %d\n", ran);
sleep(ran);
exit(ran);
}
}
for(i = 0; i < atoi(argv[1]); i++) {
int status = 0;
pid_t childpid = wait(&status);
printf("Parent knows child %d is finished. \n", (int)childpid);
}
}
Let's say i have a main C program that has to wait for sigchld of two children, and that these two sons have to do two separate task, for example one should write "1", and the other
one should write "2" ,wait 2 seconds and then terminate, now how should I write the code so that the father write his children's pid only after the two sons ends with sigchld? It's obvious that i'm missing some theory, if you look at my code you will understand what my issue is.
After that i'll have to force the execution of the second son before the first son, suggestion?
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
int pids[2], cpid, i, status;
char buff[200];
for(i=0; i < 2; i++)
{
if ((pids[i] = fork()) < 0)
perror("errno");
else
{
//child
if (pids[i] == 0)
{
if(i == 0)
write(1,"1\n", 2);
else
{
sleep(2);
write(1,"2\n", 2);
}
return 0;
}
}
}
for(i = 0; i < 2; i++)
{
cpid = waitpid(pids[i], &status, 0);
if (WTERMSIG(status))
printf("status:%d , pid terminated:\n", status,cpid);
else
printf("error: not exited with a signal\n");
}
return 0;
}
If the last for loop is changed as:
for(i = 0; i < 2; i++)
{
cpid = waitpid(pids[i], &status, 0);
if (WIFEXITED(status))
printf("status:%d , pid %d terminated normally :\n", status,cpid);
else if (WTERMSIG(status))
printf("status:%d , pid %d terminated by signal:\n", status,cpid);
else
printf("error: not exited with a signal\n");
}
Then the thing works better, as there is no signal to terminate the childs.