I'm trying to write a small program that forks processes from a single parent. Currently my code does this a few times but then the children create more child processes, which I want to eliminate.
int main() {
pid_t c;
for (int i = 0; i < 5; i++) {
c = fork();
if(c < 0) {
perror("fork");
exit(1);
}
else if( c > 0 ) {
printf("parentID = %d, childID = %d\n", getppid(i), getpid(i));
}
}
}
I'm not sure how to modify it so that fork is only forking from the parent though.
EDIT: thanks for the help, got the solution:
int main() {
pid_t c;
for (int i = 0; i < 5; i++) {
c = fork();
if(c < 0) {
perror("fork");
exit(1);
}
else if( c > 0 ) {
printf("parentID = %d, childID = %d\n", getppid(i), getpid(i));
}
else {
exit(0);
}
}
}
nothing in the posted code is recognizing the child (0 == pid)
so a child hits (and skips) the two 'if' statements.
hits the end of the loop,
branches back to the top of the loop, calls fork()....etc.
Suggest: adding
elseif( 0 == pid )
{ // then child ...
exit( EXIT_SUCCESS );
}
The child process does not enter any part of the if block, and just loops back to the top of the for loop creating more children. Also, the if (n > 0) block gets run for the parent, not the child, since fork returns 0 to the parent and the child's pid to the parent.
Change if (n > 0) to if (n == 0), and call exit() at the bottom of the block to prevent the child from continuing. Also, getpid() and getppid() don't take any arguments.
int main() {
pid_t c;
for (int i = 0; i < 5; i++) {
c = fork();
if(c < 0) {
perror("fork");
exit(1);
}
else if( c == 0 ) {
printf("parentID = %d, childID = %d\n", getppid(), getpid());
exit(0); // <-- here
}
}
}
Related
I've included code that creates a series of child processes to divide the work for a task. There's a random chance for it to terminate (handled by the word_count function from which it calls abort()) and on this event, it should create a new child process to replace it. However, the program is being blocked on the read. I know this code is messy, but I want understand the problem before cleaning it up.
int pipes[nChildProc][2]; //pipe fd[0] is read end, fd[1] is write end
long child_f_size = fsize / nChildProc;
pid_t pids[nChildProc];
//start dividing the work among child processes
for(int i = 0; i < nChildProc; ++i) {
//srand(time(NULL));
//int crash = ((rand() / RAND_MAX + 1.0) < crashRate) ? 1 : 0;
if(pipe(pipes[i]) != 0) {
printf("Failed to create pipe.\n");
exit(1);
}
pid_t pid = fork();
FILE *child_fp;
pids[i] = pid;
if(pid < 0) {
printf("Failed to create child process.\n");
exit(1);
}
else if(pid == 0) { //child process
count_t temp_count = readFromFile(child_fp, fsize, child_f_size, char* name, int i, int nChildProc);
//IPC with the main process
if(write(pipes[i][1], &temp_count, sizeof(temp_count)) == -1)
printf("failed to write to pipe.\n");
close(pipes[i][1]);
close(pipes[i][0]);
exit(0); //deallocate process' memory space
}
}
//wait for a children to finish
int ret, status, i = 0;
while(wait(NULL) != -1) { // while there are children to wait on
ret = waitpid(pids[i], &status, WUNTRACED);
if(ret == -1) {
continue;
}
if(ret != 0) {// didn't exit normally
if(pipe(pipes[i]) != 0) {
printf("Failed to create pipe.\n");
exit(1);
}
pid_t pid = fork();
FILE *child_fp;
pids[i] = pid;
if(pid < 0) {
printf("Failed to create child process.\n");
exit(1);
}
else if(pid == 0) { //child process
count_t temp_count = readFromFile(child_fp, fsize, child_f_size, char* name, int i, int nChildProc);
//IPC with the main process
if(write(pipes[i][1], &temp_count, sizeof(temp_count)) == -1)
printf("failed to write to pipe.\n");
close(pipes[i][1]);
close(pipes[i][0]);
exit(0); //deallocate process' memory space
}
}
i = (i + 1) % nChildProc;//loop back to detect more processes that were terminated
}
long bytes;
count_t temp;
temp.linecount = 0;
temp.wordcount = 0;
temp.charcount = 0;
//add up all the values from children to count
printf("time to read.\n");
for(unsigned int j = 0; j < nChildProc; ++j) {
if((bytes = read(pipes[j][0], &temp, sizeof(temp))) < 0) {//blocked here
printf("Failed to read from pipe {%d}.\n", j);
exit(1);
}
if(bytes != 0) {
count.linecount += temp.linecount;
count.wordcount += temp.wordcount;
count.charcount += temp.charcount;
}
close(pipes[j][1]);
close(pipes[j][0]);
}
A couple of issues jump out:
if(ret != 0) {// didn't exit normally you've confused ret (which is the pid) for status (which is the exit code of the child)
You can't call wait on a process twice, since calling wait allows the system to release the resources associated with the process. You have several options on how to rewrite this code:
while(wait(NULL) != -1) { // while there are children to wait on
ret = waitpid(pids[i], &status, WUNTRACED);
One easy way is to use wait then lookup in the array which index it belongs to.
while((pid = wait(&status)) {
if (pid == -1) { // no children to wait on
break;
}
for(int i = 0; i < nChildProc; ++i) {
if (pid == pids[i]) break;
}
if (i >= nChildProc) {
unexpected_pid_do_something_smart();
}
// Leave the rest of the loop the same
Note: I didn't compile or test the above code.
My program has to create multiple children, i take the number of children from terminal. Then, I need to group them and every group has different tasks.
I created the children but the problem is that I can't give them separated tasks, I can't distinguish children. Only thing I can do is, every children works on the same part(like printing pids).
How can I separate them and give them specific tasks?
For example, first 4 children should call a function, other 3 should print something and other 3 should write to a file etc.
pid_t pid[10];
pid[0] = fork();
if(pid[0] > 0)
{
for(int i = 0; i < 9; i++)
{
if(pid[i] > 0)
{
pid[i + 1] = fork();
}
}
}
for(int i = 0; i < 10; i++)
{
if(pid[i] == 0)
{
printf("child %d, parent %d\n", getpid(), getppid());
exit(1);
}
}
I think you should take a look at how the fork() function works. Here is the man page, here a useful answer and here a useful tutorial.
When you use fork() in your code, know that the child process continue from where the parent was. So when you call fork() in the first for loop, all the child processes continue the loop that the parent has begun. I don't think this is the behavior you expect.
Anyway, here's a possible solution for your problem. In this way your processes do some stuff divided in small groups. Note the exit(0) function at the end of the work. It is important to be sure that every process does only its work and not also its parent's work:
pid_t pid[10];
for (int i = 0; i < 9; i++)
{
pid[i] = fork();
//First group
if (pid[i] == 0 && i < 4){
//Insert here the code for the first group or call a fuction
exit(0);
}
//Second group
if (pid[i] == 0 && i >=4 && i < 8){
//Insert here the code for the second group or call a fuction
exit(0);
}
//Third group
if (pid[i] == 0 && i >=8){
//Insert here the code for the third group or call a fuction
exit(0);
}
if (pid[i] < 0){
perror("Something wrong with the fork");
exit(1);
}
}
int flag = 0;
flag |= (fork() == 0) << 0;
flag |= (fork() == 0) << 1;
flag |= (fork() == 0) << 2;
printf("this process works on problem %d\n", flag);
I'm trying to use the multiple fork() calls to create several children with different task
I found a code on
Multiple child process
Which is really close for what I want , yet I couldn't fully understand it
pid_t firstChild, secondChild;
firstChild = fork();
if(firstChild != 0)
{
// In parent
secondChild = fork();
if(secondChild != 0)
{
// In parent
}
else
{
// In secondChild
}
}
else
{
// In firstChild
}
My questions are:
How many process have been created (I assume that we have 4 since it's 2 forks!)?
In this part of the code
firstChild = fork();
if(firstChild != 0)
{
// In parent
secondChild = fork();
if(secondChild != 0)
{
// In parent
}
Does "//in parent" mean both of them are the same process (they have the same PID when I tried to test it).
How can I create 3 children using 2 forks?( I can draw the tree that ends with 4 leaves 3 of them are children and 1 parent)
Thank you (please feel free to tell me if I'm not totally getting the Fork concept)
How many process have been created (I assume that we have 4 since it's 2 forks!)?
Depending on the result of your forks it should be 0 to 2. Probably 2 if nothing goes wrong. There's a parent process that forks 2 children processes.
Does "//in parent" mean both of them are the same process (they have the same PID when I tried to test it).
Yes. In your case the code is checking for a return value of fork being non zero. That's not a very good idea since it covers 2 distinct cases:
It could be less than zero indicating an error, or ...
It could be greater than zero indicating to the parent the pid of the newly spawned process
Anyway ... considering all goes well and both the forks succeed, you will end up with a parent process having 2 different children.
How can I create 3 children using 2 forks?( I can draw the tree that ends with 4 leaves 3 of them are children and 1 parent
Something like this should do the trick:
firstChild = fork();
if (firstChild < 0) {
exit(EXIT_FAILURE);
perror("fork");
}
secondChild = fork();
Notice that by not checking the return value of fork() any more I'm getting a child process continuing execution at the same place as the parent. So the next fork will actually be executed by both the parent and the children each spawning a new process. So I'll get something like this ...
parent─┬─child1───(child1's child)
└─child2
I can't think of any way you can get this with only 2 forks though:
parent─┬─child1
├─child3
└─child2
Note: It's customary on stackoverflow to only limit yourself to one question per topic.
The following code shows how to create 4 process (1 parent 3 children) with only 2 forks
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int *list;
void calculate_average(int );
void calculate_maximum(int);
void calculate_minimum(int);
void calculate_average(int count)
{
int i, total = 0;
for (i = 0; i < count; i++)
total += list[i];
double average = total / count;
printf("average is %f\n",average);
}
void calculate_maximum(int count)
{
int i;
int maximum = list[0];
for (i = 1; i < count; i++)
if (list[i] > maximum)
maximum = list[i];
printf("maximum is %d\n",maximum);
}
void calculate_minimum(int count)
{
int i;
int minimum = list[0];
for (i = 1; i < count; i++)
if (list[i] < minimum)
minimum = list[i];
printf("minimum is %d\n",minimum);
}
int main(int argc, char *argv[])
{
pid_t pid, pid1;
int num_of_args = argc-1;
int i;
/* allocate memory to hold array of integers */
list = malloc(sizeof(int)*num_of_args);
for (i = 0; i < num_of_args; i++)
list[i] = atoi(argv[i+1]);
printf("The %d number of input ingeters are\n",num_of_args);
for (i = 0; i < num_of_args; i++)
printf("%d\n",list[i]);
/* fork a child process */
pid = fork();
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed\n");
return 1;
}
else if (pid == 0) { /* P2 */
pid1=getppid();
calculate_average(num_of_args);
}
else { /* P1 */
pid1=getpid();
wait(NULL);
}
pid = fork();
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed\n");
return 1;
}
else if (pid == 0) { /* could be either P3 or P4 */
if (getppid() == pid1) { /* P3 */
calculate_minimum(num_of_args);
}
else { /* P4 */
calculate_maximum(num_of_args);
}
}
else {
wait(NULL);
}
return 0;
}
Note that one of the children will be a parent for a grandchild
int proc_create(int n)
{
int pid;
n = n+1;
printf("The parent process id: %d\n", getpid());
while(1)
{
if(pid=fork() < 0){
perror("Fork Failed!");
exit(1);
}else{
printf("The child process ID is: %d\n", pid);
}
}
}
I have written the above function that will create n child processes and each child processes will print out it's own child id. Can someone tell me the flaws and how i can improve the above function.
n is a local variable, so you just do n + 1 which doesn't change anything.
It creates infinite child processes, because the fork is inside a while(1) loop
int *proc_create(int n) {
int *childs = malloc(sizeof *childs * n);
printf("The parent process id: %d\n", getpid());
for (int i = 0; i < n; i++) {
int pid = fork();
if (pid < 0) {
perror("Fork Failed!");
exit(1);
} else if (pid == 0) {
return NULL;
} else {
childs[i] = pid;
printf("The child process ID is: %d\n", pid);
}
}
return childs;
}
This process spawn N children, when they return from proc_create() they will return NULL. The parent will return an array with the pids of its N children.
I have found examples of how to fork multiple children by having something like this:
if ( fork() = 0 ) {
//In child
} else {
if ( fork() = 0 ) {
//in second child
But if I don't know how many children I am going to need, how might I do this?
For instance, if I have a linked list of commands, and I want to fork and exec for each of them... So I guess I need to know which child it is as well...
Taking you at your word that you need to do this for a linked list:
linked_list_of_commands_t *node = root;
while (node != NULL) {
int pid = fork();
if (pid == -1) {
break; // handle error
} else if (pid == 0) {
// child
execv(node->command, node->argv);
exit(1); // execv should not return, but just in case the execv call fails
} else {
node = node->next;
}
}
This will launch a separate process for every item in the list.
But the number of routines would have to be fixed, even if the execution over those branches is unbounded. So what about a while loop with some sort of switch statement logic to each routine?
How about
for (i=0; i< 1000; i++) {
pid = fork();
if (pid) {
// Error handling for pid==-1
break;
}
// Some logic dependent on value of 'i'
}
for(i = 0; i < num_children_to_spawn(); ++i) {
pid_t pid = fork();
if (pid == -1) {
exit(-1); /* error */
} else if (pid == 0) {
/* child */
do_child_things();
break;
} else {
/* parent */
}
}
Note that I didn't use a switch() because it would make it more cumbersome to break out of the loop.
pid_t children_pids[MAX_CHILDREN];
int last_child_index = 0;
for (int i=0; i < num_wanted_children; i++) {
pid_t pid = fork();
if (pid == 0)
// in child
else
children_pids[last_child_index++] = pid;
}