System call how to make parent wait for child - c

This is my code system call in C.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int n;
int i;
pid_t pid;
int time = 1000;
int sum = 0;
int main(void) {
printf("n: ");
scanf("%d", &n);
pid = fork();
if (pid < 0) {
printf("Fork Failed");
exit(-1);
} else if (pid == 0) {
//child
for (i = 1; i <= n; i++) {
sum += i;
}
printf("Sum of 1 to %d: %d\n", n, sum); // this is ok
} else {
// parent
wait(&time);
printf("Sum of 1 to %d: %d\n", n, sum); // this always return 0;
}
return 0;
}
I don't know why in parent's code block, the sum is always equal to 0.
How to make parent wait for child or am I doing something wrong ?

Waiting for the child works. However, your expectations are wrong.
Apparently you think that computations in the child process after the fork are visible in the parent process. They are not. The child is a new copy of the parent program at the time of fork. At that time, the parent's sum is 0 and stays that way.
There are several mechanisms to pass data from child to parent (the search term is interprocess communication, IPC).
exit() status
files
shared memory
pipes
signals
message queues
anything else I have missed

The issue here is the variable sum is not shared by the parent & child process, after fork() call the child will have its own copy of the variable sum.
Use shmget(),shmat() from POSIX api. Or use pthread which will share the same memory space for the newly created thread.
Update---
Added the shared memory to your code hopes this helps.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/shm.h>
int n;
int i;
pid_t pid;
int time = 1000;
int main(void) {
int shmid;
int *sum;
printf("n: ");
scanf("%d", &n);
/*request the shared memory from the OS using the shmget()*/
shmid = shmget(IPC_PRIVATE, sizeof(int), 0777|IPC_CREAT);
pid = fork();
if (pid < 0) {
printf("Fork Failed");
exit(-1);
} else if (pid == 0) {
//child
/* shmat() returns a char pointer which is typecast here
to int and the address is stored in the int pointer. */
sum = (int *) shmat(shmid, 0, 0);
for (i = 1; i <= n; i++) {
*sum += i;
}
printf("Sum of 1 to %d: %d\n", n, *sum); // this is ok
/* each process should "detach" itself from the
shared memory after it is used */
shmdt(sum);
} else {
// parent
wait(&time);
sum = (int *) shmat(shmid, 0, 0);
printf("Sum of 1 to %d: %d\n", n, *sum); // this always return 0;
shmdt(sum);
/*delete the cretaed shared memory*/
shmctl(shmid, IPC_RMID, 0);
}
return 0;
}
Refer for more info- https://man7.org/linux/man-pages/man2/shmget.2.html

Related

using Pipes create N child and send message to parent

I'm trying to create n child with the same parent, and send the random number from child -> parent.
For now, I have a problem to send random 0/1 from child -> parent.
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
pid_t pids[10];
int i;
int n = 10;
/* Start children. */
for (i = 0; i < n; ++i) {
if ((pids[i] = fork()) < 0) {
perror("fork");
abort();
} else if (pids[i] == 0) {
// printf("I am a child with id %d and my parent %d\n",getpid(),getppid());
int random = rand() % 2;
printf("\nChild send random: %d\n",random);
write(pids[1], &random, sizeof(random));
exit(0);
}
else{
int ran;
read(pids[0], &ran, sizeof(ran)); // read from child
printf("\nParent Received: %d\n", ran);
}
}
wait(NULL);
}
The problems are:
first, read and write don't want a pid like first argument but a file descriptor and second, for passing something between two processes you should use a IPC mechanism like pipes:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>
#include <time.h>
int main()
{
pid_t pids[10];
int _pipe[2];
int i;
int n = 10;
int random;
srand(time(NULL));
/* Start children. */
for (i = 0; i < n; ++i) {
//printf("%d\n",i);
pipe(_pipe);
if ((pids[i] = fork()) < 0) {
perror("fork");
abort();
} else if (pids[i] == 0) { // Child
random = rand() % 2;
char str[2];
sprintf(str,"%d",random);
//printf("\nChild send random: %d\n",random);
close(_pipe[0]);
write(_pipe[1], str, sizeof(str));
printf("Pipe sended: %s\n",str);
exit(0);
}
else{ // Parent
char string[1];
close(_pipe[1]);
read(_pipe[0],string,sizeof(string)); // read from child
printf("pipe received: %s\n",string);
//printf("\nParent Received: %d\n", ran);
}
}
wait(NULL);
}

How do I print stored data from the shared memory?

I have the following program:
#include <stdio.h>
#include <sys/types.h>
#define MAX_COUNT 100
void ChildProcess(void);
void ParentProcess(void);
void main(void)
{
pid_t pid;
pid = fork();
if (pid == 0)
ChildProcess();
else
ParentProcess();
}
void ChildProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf(" This line is from child, value = %d\n", i);
printf(" *** Child process is done ***\n");
}
void ParentProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf("This line is from parent, value = %d\n", i);
printf("*** Parent is done ***\n");
}
I have to modify it in a way that both the parent and the child print stored data from the shared memory in the following way:
Create and initialize the shared memory in the parent.
Fill the shared memory with 5 integer numbers. (I should allocate enough shared memory to store the 5 ints.)
Fork from the parent to the child.
If fork is successful, then the child process must print the values stored in the shared memory as shown in the expected output where N1, N2, N3, N4, N5 are the numbers found in the shared memory.
Expected output
What I did in the ParentProcess function is the following:
void ParentProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf("This line is from parent, value = %d\n", i);
printf("*** Parent is done ***\n");
int localVar = 0;
int* p = (int*) malloc(2);
pid_t childPID = fork();
*p = 0;
if (childPID >= 0)
{
printf("\nChild process has started\n");
if (childPID == 0)
{
localVar++;
globalVar++;
printf("Child process has found the following data %d,", *p);
*p = 70;
printf( " %d,", *p);
*p = 66;
printf(" %d,", *p);
*p = 51;
printf(" %d,", *p);
*p = 90;
printf(" %d in shared memory\n",*p);
printf("Child is existing\n\n");
}
}
}
And now I realize that I did it completely wrong but I have no idea how to fix that. I suppose I have to use shmget to create the shared memory, but then what? How do I store values in it?
If you find that you cannot help me with this or it is too long, please share sources where I can learn more about C programming in Linux, particularly regarding the usage of shared memory. Thank you in advance
It may be better to make it clear what you want to do first because as far as I read your code you call fork() twice in your code (once in main() function and once in ParentProcess() function)
So I write general solution for parent/child shared memory. There are several ways to achieve shared memory but this is one example which is modified version of the code here
How to use shared memory with Linux in C
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
void *create_shared_memory(size_t size)
{
int protection = PROT_READ | PROT_WRITE;
int visibility = MAP_SHARED | MAP_ANONYMOUS;
return mmap(NULL, size, protection, visibility, -1, 0);
}
int main()
{
// Allocate 4 ints
void *shmem = create_shared_memory(sizeof(int)*4);
if( shmem == NULL ){
fprintf(stderr, "Failed to create shared memory\n");
return -1;
}
// Initialize 4 ints
((int*)shmem)[0] = 10;
((int*)shmem)[1] = 100;
((int*)shmem)[2] = 1000;
((int*)shmem)[3] = 10000;
int pid = fork();
if (pid == 0)
{
// Print 4 ints in child
printf("Child reading int 0: %d\n", ((int*)shmem)[0]);
printf("Child reading int 1: %d\n", ((int*)shmem)[1]);
printf("Child reading int 2: %d\n", ((int*)shmem)[2]);
printf("Child reading int 3: %d\n", ((int*)shmem)[3]);
printf("Child end\n");
}
else
{
printf("Parent waiting for child ends...\n");
waitpid(pid, NULL, 0);
printf("Parent ends\n");
}
int ret = munmap(shmem, sizeof(int)*4);
if( ret != 0 ){
fprintf(stderr, "Failed to unmap shared memory\n");
return -1;
}
return 0;
}
I've written a small piece of c code which you might find helpful:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define NUM_INTS 5
int main(int argc, char *argv[])
{
key_t key = (key_t) 123456;
int shmgetrc, semgetrc;
struct shmid_ds ds;
int *shared_values;
int i;
struct sembuf sops[2];
int semid;
sops[0].sem_num = 0; /* Operate on semaphore 0 */
sops[0].sem_op = 0; /* Wait for value to equal 0 */
sops[0].sem_flg = 0;
sops[1].sem_num = 0; /* Operate on semaphore 0 */
sops[1].sem_op = 1; /* Increment value by one */
sops[1].sem_flg = 0;
/* create SHM segment */
shmgetrc = shmget(key, NUM_INTS * sizeof(int), IPC_CREAT | IPC_EXCL | 0x180);
if (shmgetrc < 0) {
perror("shmget failed...");
exit(1);
}
/* retrieve the address of the segment */
shared_values = (int *) shmat(shmgetrc, NULL, 0);
/* create a semaphore */
semgetrc = semget(key, 1, IPC_CREAT | IPC_EXCL | 0x180);
if (semgetrc < 0) {
perror("semget failed...");
exit(1);
}
/* lock the semaphore */
if (semop(semgetrc, sops, 2) == -1) {
perror("semop lock failed ...");
exit(1);
}
/* fill it with values */
for (i = 0; i < NUM_INTS; ++i) {
shared_values[i] = i;
}
/* unlock the semaphore */
sops[0].sem_op = -1;
if (semop(semgetrc, sops, 1) == -1) {
perror("semop release failed ...");
exit(1);
}
/* here something else could happen */
sleep(60);
/* lock the semaphore */
sops[0].sem_op = 0;
if (semop(semgetrc, sops, 2) == -1) {
perror("semop lock failed ...");
exit(1);
}
/* print values */
for (i = 0; i < NUM_INTS; ++i) {
printf("%d ", shared_values[i]);
}
printf("\n");
/* unlock the semaphore */
sops[0].sem_op = -1;
if (semop(semgetrc, sops, 1) == -1) {
perror("semop release failed ...");
exit(1);
}
/* remove the semaphore */
if (semctl(semgetrc, semgetrc, IPC_RMID) < 0) {
perror("semctl failed ...");
exit(1);
}
/* remove shm segment again */
if (shmctl(shmgetrc, IPC_RMID, &ds) < 0) {
perror("shmctl failed ...");
exit(1);
}
exit(0);
}
It was not my intention to write the most beautiful code ever written, just an example that shows:
how to create a shm segment
how to retrieve the address and to use it
how to remove it
Additionally, I've used a semaphore to protect the access.
Contrary to the other answer, I've used the ipc interface, not mmap().

static variables in multiple processes (Signals)

I have 2 processes running test.c. There is a signal handler in test.c which executes an execlp. In test.c, I have a static variable which needs to be only initialized once, and incremented each time before the execlp call. When either process reaches 99, they exit.
Unfortunately, right now, it's not getting incremented, my guess is because there are 2 processes that each have a copy of the static variable. Here is test.c:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
static int i = 0;
static int foo(int j)
{
printf("In the foo...\n");
j++;
printf("%d\n", j);
return j;
}
void main(int argc, char *argv[])
{
int pid, pid2, k;
int *h = malloc(sizeof(int));
int g = 0;
h = &g;
static char s[15];
pid = fork();
if (pid > 0)
{
sleep(1);
}
if (pid == 0)
{
k = foo(*h);
sprintf(s, "%d", k);
if (k >= 99)
{
printf("k=99\n");
exit(0);
}
execlp("./a.out", "forktest", s, NULL);
}
pid2 = fork();
if (pid2 == 0)
{
k = foo(*h);
sprintf(s, "%d", k);
if (k >= 99)
{
printf("k=99\n");
exit(0);
}
execlp("./a.out", "forktest", s, NULL);
}
wait(pid2);
wait(pid);
}
Can anyone please explain why there is an infinite loop? Why isn't the static variable get incremented?
Thank you.
Use Interprocess communication concepts (pipe, fifo, shared memory) here, execlp function overwrites memory of current program with new program. So when ever you call execlp gets called your program get refreshed and starts from begining and static int i is always 0.
I recommend to use pipe Refer this.
You need to use memory projection (mmap function) if you want to use the concept of shared memory between process.
In your code, the variable 'h' is the shared variable between the three process.It should defined using mmap function and initialized in the main process and then incremented in the two child process.
The answers to your two questions are related: either of the two child process never exits (exit(0)) because the if(k>=99) is never statisfied. This is due to the non-shared variable h which doesn't get incremented.
I will rather use a while loop and a return type main function.
By the way, you don't need the 'g' varibale, you can initialize directly 'h'. And there is no need of declaring the function foo as static (static functions are only useful when you want them to visible only with the file where they are defined). The buffer 's' can be declared non static (it is only a buffer which contains the value of k)
Here is a modified version of your code, it compiles and works fine.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
int foo(int* j)
{
printf("In the foo...\n");
(*j)++;
printf("%d\n", *j);
return *j;
}
int main(void)
{
int pid, pid2, k;
char s[15];
int * h = (int*)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (h == MAP_FAILED) {
printf("map failed\n");
return -1;
}
*h = 0;
pid = fork();
if (pid < 0) {
printf("fork failed pid\n");
return -1;
}
if (pid > 0) {
sleep(1);
}
else {
while(1) {
k = foo(h);
sprintf(s, "%d", k);
if (k>=99) {
printf("k>=99\n");
printf("%s\n", s);
exit(0);
}
execlp("./a.out", "forktest", s, NULL);
}
}
pid2 = fork();
if (pid2 < 0) {
printf("fork failed pid2\n");
}
if (pid2 > 0) {
sleep(1);
}
else {
while(1) {
k = foo(h);
sprintf(s, "%d", k);
if (k>=99) {
printf("k>=99\n");
exit(0);
}
execlp("./a.out", "forktest", s, NULL);
}
}
wait(pid);
wait(pid2);
return 0;
}
Here is the output (only the last strings) click on the link:
output

fork() created process don't execute in parallel

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;
}

creating a second process in C

Im new in C programming and i have to do this:
Write a program that creates a second process, and then in both processes outputs the process ID and the owners user ID.
I don't know if thats right and how to continue from here. Here is what i have:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(void) {
int ChildPID;
printf("This is the parent process number %d\n",getpid());
if ((ChildPID = fork()) == -1) {
perror("Could not fork");
exit(EXIT_FAILURE);
}
if (ChildPID == 0) {
//----In the child process
printf("This is the child process, number %d parent number %d\n", getpid(), getppid());
}
return(EXIT_SUCCESS);
}
The piece of code given below gives your solution. Here you can clearly identify parent code and child process code. Both are printing their corresponding pids.
void ExecuteChild(void);
void ExecuteParent(void);
int main(void)
{
pid_t pid;
pid = fork();
if (pid == 0)
ExecuteChild();
else
ExecuteParent();
}
void ExecuteChild(void)
{
int i;
for (i = 1; i <= 200; i++)
printf("CHILD[%d]: UserID[%d] printing - %d\n", getpid(),getuid(),i);
printf(" ------------- Child Exiting -------------\n");
}
void ExecuteParent(void)
{
int i;
for (i = 1; i <= 200; i++)
printf("PARENT[%d]: UserID[%d] printing - %d\n", getpid(),getuid(),i);
printf(" ------------- Parent Exiting -------------\n");
}

Resources