This is a homework question. I have to write a program forking itself 20 times. Each new process is adding +1 to a variable (integer) which is shared between all of them. The thing is, I have to use semaphores (IPC). This piece of code is 'working' - giving the value of 20 in the end.
*buf = 0;
for(i=1; i<=20; ++i)
{
if(fork()!=0)
{
*buf += 1;
exit(0);
}
}
EDIT:
Based on this code I am trying to get output like :
I am child 1...
I am child 2...
.
.
.
I am child 20...
It worked once (first time), and then the order became random. But I did not change any code. What am I doing wrong?
Well your major problem is this:
if (fork()!=0) //<-- this
fork() will return -1 on error, the parent pid, OR ZERO for the child. So you are actually doing everything in the parent. Change to (fork() ==0) and it does what you want.
Also you should wait on your children and detach shared memory. (I added some output of the process ids to make it a little clearer.)
printf("I AM THE PARENT pid = %d\n", getpid());
*buf = 0;
for(i=1; i<=20; ++i)
{
if((pid = fork()) == -1)
{
perror("fork");
exit(1);
}
if (pid == 0)
{
v(semid, 0);
*buf += 1;
p(semid, 0);
printf("I am child %d with pid = %d\n", i, getpid());
shmdt(buf);
exit(0);
}
}
for (i = 1; i <= 20; ++i)
{
pid = wait(&status);
printf("child pid = %d reaped\n", pid);
}
printf("buf: %p\n", buf);
printf("*buf: %d\n", *buf);
shmdt(buf);
return 0;
Related
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 want to have a parent process and three child processes. I want these child processes to know the pids of the other child processes.
The problem is that when I do fork and then I do it again, the second fork is also executed in the child process creating an extra process (or so I think).
How could I solve it?
Thanks.
The parent should fork three times, the children should not fork. This way, the parent will know the pids of all three children.
After the fork, you'll need some kind of separate communication channel by which the parent can communicate these pids to all children. A simple way would be to open a pipe (see pipe(2)) before forking each child, so the child inherits the pipe's file descriptor (at least the read end) and the parent keeps the write end. Then have the parent send the three pids down each pipe and close it.
Example code (long, but that's the nature of C):
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define NUM_CHILDREN 3
/* Entry point for the child processes */
int child_main(int pipe_read_end) {
pid_t my_pid = getpid();
/* Read child pids from pipe */
int child_pids[NUM_CHILDREN];
unsigned int bytes_read = 0;
while (bytes_read < sizeof(child_pids)) {
ssize_t result = read(pipe_read_end, ((unsigned char *) child_pids) + bytes_read, sizeof(child_pids) - bytes_read);
if (result < 0) {
perror("error reading from pipe");
return 1;
} else if (result == 0) {
fprintf(stderr, "unexpected end of file\n");
return 1;
} else {
bytes_read += result;
}
}
close(pipe_read_end);
/* Do something useful with these child pids */
for (int i = 0; i < NUM_CHILDREN; i++) {
printf("Child %d received sibling pid %d\n", my_pid, child_pids[i]);
}
return 0;
}
/* Entry point for the parent process. */
int main() {
int child_pids[NUM_CHILDREN];
int pipe_write_ends[NUM_CHILDREN];
for (int i = 0; i < NUM_CHILDREN; i++) {
/* Create the pipe for child i */
int pipefd[2];
if (pipe(pipefd)) {
perror("error creating pipe");
return 1;
}
int pipe_read_end = pipefd[0];
int pipe_write_end = pipefd[1];
/* Fork child i */
pid_t child_pid = fork();
if (child_pid < 0) {
perror("error forking");
return 1;
} else if (child_pid == 0) {
printf("Child %d was forked\n", getpid());
close(pipe_write_end);
return child_main(pipe_read_end);
} else {
printf("Parent forked child %d\n", child_pid);
close(pipe_read_end);
pipe_write_ends[i] = pipe_write_end;
child_pids[i] = child_pid;
}
}
/* Send pids down the pipes for each child */
for (int i = 0; i < NUM_CHILDREN; i++) {
unsigned int bytes_written = 0;
while (bytes_written < sizeof(child_pids)) {
ssize_t result = write(pipe_write_ends[i], ((unsigned char *) child_pids) + bytes_written, sizeof(child_pids) - bytes_written);
if (result < 0) {
perror("error writing to pipe");
return 1;
} else {
bytes_written += result;
}
}
close(pipe_write_ends[i]);
}
/* Wait for children to exit */
for (int i = 0; i < NUM_CHILDREN; i++) {
if (waitpid(child_pids[i], 0, 0) < 0) {
perror("error waiting for child");
return 1;
}
}
}
As #PSkocik points out in their answer, you should probably not be doing this. Pids can be reused by the OS, so there's no way for the children to know that their sibling pids still actually refer to their siblings; only the parent can be sure, because it has to wait for each pid before it can be reused.
However, this same mechanism can be used for other forms of IPC (inter-process communication); you could, for example, use it to create pipes between the children directly.
You can use shared memory or some other kind of IPC to communicate the PIDs, but you probably shouldn't even try.
PIDs are subject to recycling and you can only ever know for sure if a PID refers to the process you think it refers to if that PID belongs to a child process of yours (because then you can know if you've waited on it or not).
Otherwise, PIDs (of non-children) are racy references which are basically only usable for hacky debugging.
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 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;
}
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));
}