shared memory with fork() - c

I would like to use shared memory with fork() but I can't seem to get the result I want.
So I have a car Structure array and I would like to put it in shared memory in order to use fork(). Then I want to run 10 fork() and wait until all the kids are done to display the results! (the result is just their total time of each car, it is different because I am generating a random number for each car).
The problem is when I printf() I have the same value for everyone, whereas it must be different for each child! because i tested with just a loop so without shared memory it works fine but i have to use shared memory;).
Could anyone help me please
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <sys/wait.h>
#define NUMBER_OF_CARS 10
#define MIN 25000 // time generator
#define MAX 40000
typedef struct {
unsigned int totalTime;
} car;
car *shared_memory;
int drive(int i);
unsigned int generateNumber(void);
void display();
int main(void)
{
srand( time(NULL) );
/***************************************************
* Creating shared memory *
****************************************************/
int segment_id = shmget(IPC_PRIVATE, sizeof(car) * NUMBER_OF_CARS, 0666 | IPC_CREAT);
if (segment_id == -1) {
perror("shmget() failed !");
exit(EXIT_FAILURE);
}
shared_memory = shmat(segment_id, NULL, 0);
if (shared_memory == (void *) (-1)) {
perror("shmat() failed !");
exit(EXIT_FAILURE);
}
/**********************************************************
* Creation of child / cars *
**********************************************************/
int i;
pid_t pid = 0;
for (i = 0; i < NUMBER_OF_CARS; i++) {
pid = fork();
if (pid == 0)
break;
}
switch (pid) {
case -1:
perror("fork failed !");
exit(EXIT_FAILURE);
case 0:
drive(i); //540000
exit(EXIT_SUCCESS);
default:
display();
/******** wait for children to finish *********/
for (int j = 0; j < NUMBER_OF_CARS; j++) {
wait(NULL);
}
}
/******** Detach memory segments *********/
shmdt(shared_memory);
/******** Delete shared memory *********/
shmctl(segment_id, IPC_RMID, NULL);
exit(EXIT_SUCCESS);
}
unsigned int timeMaxi = 540000;
int drive( int i ) {
unsigned int number;
while ( shared_memory[i].totalTime <= timeMaxi ) //time pas dépassée
{
number = generateNumber();
shared_memory[i].totalTime += number;
}
return 0;
}
void display(void) {
for (int i = 0; i < NUMBER_OF_CARS; i++){
printf("Total %d : %d\n", i, shared_memory[i].totalTime);
}
}
unsigned int generateNumber(void)
{
return rand()%(MAX-MIN+1)+MIN;
}
The result :
./prog
Total 0 : 564634
Total 1 : 564634
Total 2 : 564634
Total 3 : 564634
Total 4 : 564634
Total 5 : 564634
Total 6 : 564634
Total 7 : 564634
Total 8 : 564634
Total 9 : 564634

There's nothing wrong with your shared memory. The problem is that all of the children are ending up with the same random number sequence in generateNumber(). You're only calling srand() once, before all the forks, so every child is going to generate the exact same random number.
Just call srand() in each child before calling drive(). srand(time(NULL)) won't be enough, because they'll likely all run within the same second, but you could use getpid() or some other appropriate method as an argument to srand() to seed the random number generator in each child differently.

Related

System call how to make parent wait for child

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

Fork two child process, one to compute sum of N and the other the factorial of N

I have to take an integer argument from the command line. Create two child processes. The first computes the sum of positive integers and the second the factorial. The parent must also wait for each child to finish, then the parent prints out "done" with its own identifier.
an output example is
[ID = 101] Sum of positive integers up to 5 is 15
[ID = 102] Factorial of 5 is 120
[ID = 100] Done
but the output I am getting is
[ ID = 4262] Factorial of 5 is 120
[ID = 4262] DONE
[ID = 4260] DONE
[ ID = 4261] sum of positive integers up to 5 is 15
This is my code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main (int argc, char * argv[])
{
pid_t ret;
int i, num,sum=0,fact=1;
ret=fork();
for(i=1;i<argc; i++){
num=atoi(argv[1]);
}
if (ret == 0) {
for(i=1;i<=num;i++){
sum+=i;
}
printf("\n [ ID = %d] sum of positive integers up to %d is %d\n",getpid(),num,sum);
}
else{
if(fork()==0){
for(i=1;i<=num; i++){
fact*=i;
}printf("\n [ ID = %d] Factorial of %d is %d\n",getpid(),num,fact);
}
wait(NULL);
printf("\n[ID = %d] DONE",getpid());
}
return 0;
}
My problem is that i'm not sure how to properly fork to have 2 child processes.
I would suggest you first to create two separate functions, sum() and fact() that implement the tasks each respective child process should perform:
void sum(int num) { /* ... */ }
void fact(int num) { /* ... */ }
Then, have pointer functions referring to those functions:
typedef (*child_task_t)(int);
child_task_t child_task[2];
child_task[0] = sum;
child_task[1] = fact;
That way, you can easily fork() to have two children by means of a for-loop:
for (int i = 0; i < 2; i++) {
switch(fork()) {
case 0: // parent
continue;
case -1: // error
return -1;
default: // child
task_child[i](num); // <-- run the task
exit(0); // child process finishes
}
}
// parent waits for the children to finish
for (int i = 0; i < 2; i++)
wait(NULL);
There is some problem in your code, I commented it:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main (int argc, char * argv[])
{
pid_t ret;
int i, num,sum=0,fact=1;
ret=fork();
for (i=1; i < argc; i++) {
num = atoi(argv[1]);
}
if (ret == 0)
{
/* in first child */
for(i=1;i<=num;i++){
sum+=i;
}
printf("\n [ ID = %d] sum of positive integers up to %d is %d\n",getpid(),num,sum);
/* here, you should exit from first child
with exit or return */
}
else
{
/* here, we are in parent */
if(fork()==0)
{
/* here, in second child */
for(i=1;i<=num; i++){
fact*=i;
}
printf("\n [ ID = %d] Factorial of %d is %d\n",getpid(),num,fact);
/* here, you should exit from second child
with exit or return */
}
/* warning, second child and parent get there */
/* warning, here you only wait for one child */
wait(NULL);
printf("\n[ID = %d] DONE",getpid());
}
return 0;
}
It's quite easy to simplify it:
isolate childs' code
identify which line will be executed by parent or child
wait for childs
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main (int argc, char * argv[])
{
pid_t ret;
int i, num,sum=0,fact=1;
/* get parameter (you should test the value of argc before) */
num = atoi(argv[1]);
/* create a first child */
if (0 == fork())
{
/* in first child */
for(i=1;i<=num;i++){
sum+=i;
}
printf("\n [ ID = %d] sum of positive integers up to %d is %d\n",getpid(),num,sum);
/* exit from first child */
exit(0);
}
/* this point will not be reached by first child */
/* create a second child */
if ( 0 == fork())
{
/* here, in second child */
for(i=1;i<=num; i++){
fact*=i;
}
printf("\n [ ID = %d] Factorial of %d is %d\n",getpid(),num,fact);
/* exit from second child */
exit(0);
}
/* this point will not be reached by second child */
/* wait for one child */
wait(NULL);
/* wait for a second child */
wait(NULL);
printf("\n[ID = %d] DONE",getpid());
return 0;
}

Segmentation Fault in C producer/consumer using messagequeue

I am doing an assignment that implements the producer / consumer problem using a UNIX message queue as the data structure shared by a single producer and three consumers. The program I am creating is supposed to create a child process and the child process will in turn create three threads. The parent process is to be the producer and the three threads will be the consumers. The number of items, N, that are to be produced will be provided to the program via the command line. After spawning the child process the parent will enter an N-iteration loop. In each iteration of the loop the parent will do the following:
1) Generate a random number, R, in the range of 0-999.
2) Send a message containing R.
3) Add R to a running total of all values produced.
4) Display the string “Producer produced a R”.
5) Put the producer to sleep for 0-1 seconds using sleep(rand()%2).
After the N iterations have completed display the string "Total produced = XXXX” (where XXXX is the sum of all R values produced) and wait for the child to terminate. It is the parent’s responsibility to create and destroy the queue.
The child process will create three consumer threads, 0, 1 and 2. Each thread will enter an N/3 iteration loop. In each iteration of the loop each consumer thread will do the following:
1) Read a message containing a value, C, consumed from the queue.
2) Add C to a running total maintained by each consumer thread.
3) Display the string “Consumer thread Z consumed a C” where Z is the thread number – 0,1 or 2.
4) Put the consumer thread to sleep for 1-3 seconds using sleep((rand()%3)+1)
After N/3 iterations display the string "Total consumed by consumer thread Z = YYYY” where YYYY is the sum of all N/3 values consumed.I am receiving a segmentation fault in the last iteration of the loop and I am not sure why. Can anyone help me with this issue?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <pthread.h>
#include <sys/sem.h>
#include <semaphore.h>
struct msgbuf {
long mtype;
int mnum;
};
int msqid;
unsigned long total;
pthread_mutex_t sem_id;
int init() {
srand (time(NULL));
msqid = msgget(IPC_PRIVATE, IPC_CREAT | 0600);
if (msqid == -1) { perror("msgget"); return EXIT_FAILURE; }
pthread_mutex_init(&sem_id, NULL);
total = 0;
return 0;
}
int producer() {
int R = rand() % 999;
struct msgbuf msg = {999, R};
if(msgsnd(msqid, &msg, sizeof(msg.mnum) + 1, 0) == -1) {
perror("msgsnd"); return -1; }
total += R;
return R;
}
void *consumer(int thread_num, int iteration) {
struct msgbuf msg;
int thread_total = 0;
while(iteration--) {
pthread_mutex_lock(&sem_id);
if (msgrcv(msqid, &msg, sizeof(msg.mnum) + 1, 0, 0) == -1)
perror("msgrcv");
thread_total += msg.mnum;
printf("Consumer thread %d consumed a %d\n", thread_num, msg.mnum);
pthread_mutex_unlock(&sem_id);
}
printf("Total consumed by consumer thread %d = %d\n", thread_num,
thread_total);
sleep((rand()%3)+1);
}
int main(int argc, char *argv[]) {
int N = argc > 1 ? atoi(argv[1]) : 10;
if (init() != 0) return EXIT_FAILURE;
for (int i=0;i<N;i++) {
int R = producer();
if(R == -1) return EXIT_FAILURE;
printf("Producer produced a %d\n", R);
sleep(rand()%2);
}
printf("Total produced = %lu\n", total);
pthread_t thread_nums[3];
for (int i=0; i<=4; i++) {
int iteration = i == 0 ? N/3 + (N%3) : N/3;
if(pthread_create(&thread_nums[i], NULL,
consumer(i, iteration), NULL) != 0) {
perror("pthread_create");
return EXIT_FAILURE;
}
}
for (int i=0;i<4;i++) pthread_join(thread_nums[i], NULL);
return 0;
}
Ok so in the main function, thread_nums has 3 "slots", where as the loop proceeding wants to go over 5 different "slots".
Also, the last loop accesses a "slot" which does not exist
Remember that an array of size [3] has only three positions. The last item is at index 2 (0,1,2), for a total of three elements.

Shared Memory - Process communication

What I have to do:
-Create a shared memory segment.
-fill an array with a fixed number of integers e.g 100
-pass these created numbers to a child process in blocks of 10 each.
-in the child process: output these numbers
So this is basically a communication between two processes via a shared memory segment.
My question: So far I can pass the first 10 numbers to the child process .. but I don't really know how to pass the next 10 numbers to the very same child process to output it without creating more child processes .. I thought maybe I could simply wrap everything in a while loop but then everytime a new child process is created which is not what I want.
Right now I have the following Code:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define N_SHARED 10
#define SIZE 100
int main(int argc, char **argv){
int shID;
int *myPtr;
int i;
int counter = 0;
int array[SIZE];
for(i=0;i<SIZE;i++){
array[i] = lrand48();
}
/* Shared Memory Creation */
shID = shmget(223520, N_SHARED, IPC_CREAT | 0666);
if (shID >= 0) {
/* get memory */
myPtr = shmat(shID, 0, 0);
if (myPtr==(int *)-1) {
perror("shmat");
} else {
/* memory is accessible */
for (i=0; i<N_SHARED; i++) {
myPtr[i] = array[counter];
counter += 1;
}
// create Child Process
pid_t child = fork();
if(child == 0){
sleep(5);
shID = shmget(223520, N_SHARED, 0666);
if (shID >= 0) {
myPtr = shmat(shID, 0, 0);
if (myPtr==(int *)-1) {
perror("shmat");
} else {
for (i=0; i<N_SHARED; i++) {
printf("%d\n", myPtr[i]);
}
shmdt(myPtr);
}
}else {
/* shmget went wrong */
perror("shmget");
}
}
/* give up memory */
shmdt(myPtr);
}
} else {
/* shmget went wrong */
perror("shmget");
}
}

2D arrays with shared memory

I have 2 programs that communicate with each other using a block of shared memory.
The first program takes an argument from the command line and forks the number of times specified, the process ID of each child and a randomly generated number are stored in a 2D array that is then supposed to be passed to the second program via the attached memory block. Problem is I have no idea how to do this and would appreciate some help as I am a bit of a novice when it comes to this.
Here is the code for the first program so far and is fully tested and working:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <unistd.h>
#include <time.h>
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("\nError with command line argument!\n");
exit(1);
}
/* Program is simulation of a printer queue, forked child processes
act as jobs in the queue with pids being the job number and a
randomly generated value being the priority order (this comes into
play in program 2) */
srand(time(null));
pid_t pid;
int amount, i, pID, rNum;
amount = atoi(argv[1]);
int procID[amount]; /* 1D array that will hold pid for each process */
int randNum[amount]; /* 1D array that will hold random number to
determine priority level of the print jobs */
int rows = amount;
int cols = 2;
int printDetails[rows][cols]; /* 2D array that will hold the values
from both 1D arrays, displaying all
data from print queue when output */
printf("\nPrint queue started:");
getchar();
for (i = 0; i < amount; i++)
{
pid = fork();
if (pid < 0)
{
perror("Error with fork!");
exit(1);
}
if (pid == 0)
{
pID = getpid();
rNum = rand()%50;
printf("\nPrint Job : %d", pID);
printf("\nPriority Level : %d\n", rNum);
procID[i] = pID;
randNum[i] = rNum;
sleep(1);
}
else
{
wait(NULL);
return 0;
}
}
printf("\n%d successful print jobs created\n", amount);
printf("\n-----PRINT DETAILS-----\n");
printf("\nJob No:\tPriority:\n");
for (i = 0; i < rows; i++)
{
printDetails[i][0] = procID[i];
printDetails[i][1] = randNum[i];
printf("%d\t%d\n", printDetails[i][0], printDetails[i][1];
}
printf("\n-----END OF LIST-----\n");
/* Create shared memory segment using shmget and shmat,
how do I insert the array above into this, like I said
complete noob! */
}
Sorry for the huge wall of code, just to help understand what I'm working with,
like I said, any help in regards to the shared memory would be much appreciated as I'm kinda outta my depth here!
Copy on write mechanism will allocate a new pointer the moment you changed it on the second process... And when it dies it will take the new allocated memory with different data with it...the solution is allocating a dynamic pointer... When you change it's values it won't allocate a new one dynamically and use the old one and change its data
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <unistd.h>
#include <time.h>
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("\nError with command line argument!\n");
exit(1);
}
/* Program is simulation of a printer queue, forked child processes
act as jobs in the queue with pids being the job number and a
randomly generated value being the priority order (this comes into
play in program 2) */
srand(time(NULL)); // null -> NULL
pid_t pid;
int amount, i, pID, rNum;
amount = atoi(argv[1]);
int* procID =(int*) calloc(amount,sizeof(int)); /* 1D array that will hold pid for each process */
if(!procID)
return -1;
int* randNum =(int*) calloc (amount,sizeof(int)); /* 1D array that will hold random number to
determine priority level of the print jobs */
if(!randNum)
return -1;
int rows = amount;
int cols = 2;
int k;
int** printDetails = (int**) calloc (rows, sizeof(int*)); /* 2D array that will hold the values
from both 1D arrays, displaying all
data from print queue when output */
if(!printDetails)
return -1;
for(k=0; k<rows;k++)
{
printDetails[k] = (int*) calloc (cols, sizeof(int));
if(!printDetails[k])
return -1;
}
printf("\nPrint queue started:");
getchar();
for (i = 0; i < amount; i++)
{
pid = fork();
if (pid < 0)
{
perror("Error with fork!");
exit(1);
}
if (pid == 0)
{
pID = getpid();
rNum = rand()%50;
printf("\nPrint Job : %d", pID);
printf("\nPriority Level : %d\n", rNum);
procID[i] = pID;
randNum[i] = rNum;
sleep(1);
}
else
{
wait(NULL);
return 0;
}
}
printf("\n%d successful print jobs created\n", amount);
printf("\n-----PRINT DETAILS-----\n");
printf("\nJob No:\tPriority:\n");
for (i = 0; i < rows; i++)
{
printDetails[i][0] = procID[i];
printDetails[i][1] = randNum[i];
printf("%d\t%d\n", printDetails[i][0], printDetails[i][1]);
}
printf("\n-----END OF LIST-----\n");
/* Create shared memory segment using shmget and shmat,
how do I insert the array above into this, like I said
complete noob! */
for(k=0; k<rows; k++)
free(printDetails[k]);
free(printDetails);
free(randNum);
free(procID);
}

Resources