I am currently learning about the fork() function in c. I was playing around with the child pid's and trying to store them within an array but keep coming across errors:
void store(int pid){
int arr[10];
int i = 0;
for(i = 0; i < 10; i++){
if(arr[i] == 0){
arr[i] = pid;
printArray(arr);
break;
}
}
}
int stuff(int a){
int status = fork();
if(status == 0){
printf("PID IS %d\n", getpid());
store(getpid());
}
else {
printf("PID IS %d\n", getpid());
store(getpid());
}
return a + 1;
}
int main(int argc, char * argv[]){
int a = stuff(10);
return 0;
}
Instead, this outputs the same array with the two different PIDS in the same array index. I am not too sure what exactly is happening here and would be grateful for any explanation.
Keep it in mind that fork function is called once but returns twice. The difference in the returns is that the return value in the child
is 0, whereas the return value in the parent is the process ID of the new child. The child process and the parent process run in separate memory spaces.
That's the reason why your program outputs the same array with the two different PIDS in the same array index.
int stuff(int a){
int status = fork();
// fork will return a value of pid_t type
pid_t status = fork();
if(status == 0){
// this is in the child process, so getpid() will return the pid of the child
printf("PID IS %d\n", getpid());
store(getpid());
}
else {
// this is in then parent process, so getpid() will return the pid of the parent
printf("PID IS %d\n", getpid());
store(getpid());
}
return a + 1;
}
Related
I've created the below code:
int main(int argc, char *argv[])
{
int i, n, N;
pid_t pid;
int status;
N = atoi(argv[1]);
for(i = 0; i < N; i++) {
pid = fork();
if(pid==0) {
srand(getpid() * getppid());
n = rand() % 10 + 1;
printf("I'm child nÂș %d with childpid %d, parent pid = %d, n = %d\n", i, getpid(), getppid(), n);
exit(n);
}
}
while ((pid = waitpid(pid, &status, 0))) {
if (pid < 0)
;
else if (WEXITSTATUS(status) < 4)
printf("exit status %d lower than 4\n", WEXITSTATUS(status));
}
wait(NULL);
return 0;
}
The idea is a parent process forking N child process and each of them exiting with a random value. I want my parent process to monitor all the child processes and fork a new child if the exit status is, for instance <4. This will be going on until all process exit with a status >= 4.
Solved creating a function copying the code from parent and child (keeping the code in main() untouched). The parent calls the function, the function forks another process, and the parent in the same function calls the function recursively under the conditions we choose.
I am currently working on a school project and I wanted to store the PID of my process in the global array id, so that I can use it in another function :
int id[3];
int main(int agrc,const char* agrv[]) {
for(int i = 0; i < 3; i++) {
if((fork() == 0)) {
id[i] = (int)getpid();
printf("ID[%d] = %d\n",i,id[i]);
if(i != 3) {
printf("I am a wharehouse. PID = [%d] PPID = [%d]\n",getpid(),getppid());
whcode();
exit(0);
}
else if(i == 3) {
printf("I am the central. PID = [%d] PPID = [%d]\n",getpid(),getppid());
central_code();
exit(0);
}
}
}
sleep(2);
printf("ID[0] = %d\n",id[0]);
printf("ID[1] = %d\n",id[1]);
printf("ID[2] = %d\n",id[2]);
}
But when I run this the output of the last 3 prints is 0, where it should be the PID of each process. Why does this happen?
On the call to fork(), new process is created with separate virtual memory space. This child process will return from the call to fork with 0, so in your code, this child will go inside the if branch and assign to id[i] it's pid. But this assignment is happening in a separate process, with separate virtual memory, so it has no effect on the parents virtual memory space and the parent will not see any change in its array. That is why your code prints the zeroes.
If you want to print the pids of the children by the parent, use the return value of fork(), which in parent is the pid of the child process. Inside the for, use code such as this:
pid_t child_id;
switch (child_id = fork()) {
case -1:
//Fork failed, exit with error or something
break;
case 0:
//Child code
printf("ID[%d] = %d\n",i,id[i]);
if(i != 3) {
printf("I am a wharehouse. PID = [%d] PPID = [%d]\n",getpid(),getppid());
whcode();
exit(0);
}
else if(i == 3) {
printf("I am the central. PID = [%d] PPID = [%d]\n",getpid(),getppid());
central_code();
exit(0);
}
break;
default:
id[i] = child_id;
break;
}
By the way, you should really declare the id array as pid_t id[3], and when printing, print it as long. That for now is probably the most portable way to handle these things.
I'm implementing a simple parent/child process program using fork. My goal is to create a user input number of child processes from a single parent and store their PIDs in a dynamic array. I manage to create the child processes (I think) using fork and store their PIDS. However, when I store the PIDs, I also store the 0 PID and what I believe another PID related to the processes yet this number is quite bigger than the child and parent.
How come this happens when clearly this is only done inside the parent process?
void createProcesses(int nProcess) {
int i;
int PID;
processIDS = calloc(nProcess, sizeof(long));
printf("*****Creating Processes*****\n");
printf("Parent Process: PID %d\n", getpid());
for (i = 0; i < nProcess; i++) {
PID = fork();
if (PID == 0) {
printf("Child Process: PID %d\n", getpid());
while(1){}
}
else if(PID != 0) {
// sleep(3);
// printf("Number of child processes created: %d\n", nProcess);
// updateProcessList();
*(processIDS + i) = PID;
printf("%d\n", PID);
}
}
for(i = 0; i < sizeof(processIDS); i++) {
printf("%ld\n", *(processIDS + i));
}
while(1) {
sleep(5);
updateProcessList();
}
}
processIDS is a long * global variable.
The problem is here:
for(i = 0; i < sizeof(processIDS); i++) {
printf("%ld\n", *(processIDS + i));
}
Because processIDS is a pointer, it's size is the size of a long *, probably 4 or 8, which is not what you want. If the value of nProcess is less than this, you'll be reading off the end of the dynamically allocated array, invoking undefined behavior.
You know there are nProcess processes created, so use that for your loop test:
for(i = 0; i < nProcess; i++) {
printf("%ld\n", *(processIDS + i));
}
I need to create a program that creates n number of processes and displays information. When each process ends, I am to print it's PID and the exit status. The way I am doing it, the parent program waits to create the next process until the current one ends. I need it so that it keeps creating the child processes and just displays the exit information when ever one process ends without blocking the parent from continuing. I can;t figure out where to put my wait to ensure this. Below is my code:
int main (int argc, char *argv[])
{
if (argc < 2)
{
printf("\n\nUsage: %s <enter a number (12 or less)>\n\n", argv[0]);
exit (-1);
}
else
{
int *processNum = (int *)malloc(sizeof(12));
int processNumTemp;
processNumTemp = atoi(argv[1]);
processNum = &processNumTemp;
if(*processNum > 12 || *processNum < 1)
{
printf("\n\nUsage: %s <enter a number (12 or lrss)>\n\n", argv[0]);
}
else
{
parentInfo(processNum);
createChildProcess(processNum);
}
}
return 0;
}
//Name: parentInfo
//Description: Displays information about the parent process
//Parameters: processNum - stores the number of child processes to create
// (entered at the command line).
//Return: none
void parentInfo(int *processNum)
{
printf("Parent process ID: %d\n", getppid());
printf("Number of processes to create: %d\n", *processNum);
}
//Name: createChildProcess
//Description: Creates n number of child processes.
// For each child process, it says its a child process and it
// displays its PID.
// After each child process closes, the parent displays info.
//Parameters: processNum - stores the number of child processes to create
// (entered at the command line).
//Return: none
void createChildProcess(int *processNum)
{
int i;
int childStatus;
pid_t childpid;
/*The for loop will create n number of processes based on the value of processNum.*/
for(i = 1; i <= *processNum; i++)
childpid = fork();
//Executes if fork didn't work
if(childpid < 0)
{
perror("fork");
exit(1);
}
//Executes if the fork worked
else if( childpid == 0)
{
int pid = getpid();
//Prints a message and the child processe's PID
printf("\nHello I am a child process.\n");
printf("My PID is %d. \n", getpid());
for(int x = 1; x <= pid; x ++);
exit(15);
}
}
//Executes after the child process has ended
//Checks the child process's exit status
waitpid(childpid, &childStatus, WUNTRACED);
printf("\nPID of the child process that was just created: %d.\n", childpid);
if(WIFEXITED(childStatus))
{
printf("PID %d exited normally. Exit number: %d\n", childpid, WEXITSTATUS(childStatus));
}
else if(WIFSTOPPED(childStatus))
{
printf("PID %d was stopped by %d\n", childpid, WSTOPSIG(childStatus));
}
else if(WIFSIGNALED(childStatus))
{
printf("PID %d exited due to signal %d\n.", childpid, WTERMSIG(childStatus));
}
else
{
perror("waitpid");
}
}
Before fork code
signal(SIGCHLD, childHandler);
In childHandler put your waitpid code.
void childHandler(int signum)
{
pid_t childpid;
int childstatus;
while ((childpid = waitpid( -1, &childstatus, WNOHANG)) > 0)
{
if (WIFEXITED(childStatus))
{
printf("PID %d exited normally. Exit number: %d\n", childpid, WEXITSTATUS(childStatus));
}
else
if (WIFSTOPPED(childStatus))
{
printf("PID %d was stopped by %d\n", childpid, WSTOPSIG(childStatus));
}
else
if (WIFSIGNALED(childStatus))
{
printf("PID %d exited due to signal %d\n.", childpid, WTERMSIG(childStatus));
}
else
{
perror("waitpid");
}
}
}
}
You should not use async-unsafe calls like printf inside a signal handler so alter your code to save the status in a global or heap allocated array - you know the size to create from processNum - and print the status info outside the handler.
Also, as currently structured, your parent could end before reaping all the children. Add a counter for the children so that you wait on all of them before the parent exits.
Look into signal SIGCHLD. If you have it blocked, you must unblock it or might instead explicitly check for it.
The purpose of wait is to, well, wait, so the way to solve your problem is to first create all the children, then start waiting for them to terminate.
Here is a program which does that:
// fork
#include <unistd.h>
// wait
#include <sys/types.h>
#include <sys/wait.h>
// exit
#include <stdlib.h>
//printf
#include <stdio.h>
void child( int id)
{
int seed= id;
int x= rand_r( &seed) % 10;
sleep( x);
exit( x);
}
int main( int argc, char *argv[])
{
const int n= 5;
int i;
printf( "creating %d children.\n", n);
for ( i= 0; i < n; ++i) {
pid_t pid= fork();
if ( !pid)
child( i); // does not return
else
printf( "child [0x%x] created.\n", pid);
}
// all the children are created now
// now we wait for them to terminate
printf( "waiting for children to terminate.\n", n);
for ( i= 0; i < n; ++i) {
int result;
pid_t pid= wait( &result);
printf( "child [0x%x] terminated with result [%u].\n", pid, WEXITSTATUS( result));
}
puts( "all children terminated.");
}
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.