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);
}
Related
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
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.
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;
}
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");
}
}
When I run shmget in the following code it is returning a value of -1 and im not sure why that is the case. Everything else seems to be running fine. The code is just supposed to take in a few digits from the command line and then create shared memory for them. The digits will range from 0 to 9.
#include <sys/ipc.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
int numArgc =(int)argc-1; //number of vauled arguments passed
int arrayId[numArgc];
pid_t pid;
int arrSpace[numArgc]; //array to store atoi of values
int status;
int *memory; //pointer to shared memory
int memoryId; //check for smhget
int childPID;
int childId;
if(argc > 8 || argc < 2) //check number of cmd line arg
{
printf("The number of arguments must be between 1 and 7");
return(0);
}
else
{
for(int i=1; i<numArgc+1; i++) //store args as integers
{
arrSpace[i]=atoi((argv[i]));
printf("%d\n", arrSpace[i]);
}
}
memoryId=shmget(IPC_PRIVATE, try, IPC_CREAT | 07546); //create shared
printf("%d \n", memoryId);
if(memoryId<0)
{
printf("There was an error with ID.\n");
return (0);
}
printf("%s%d", "Size of shared Memory of parent is \n ", numArgc);
memory=(int*)shmat(memoryId, NULL, 0); // attaches shared memory
if((long)memory == -1)
{
printf("There was an error running shmat .\n");
return (0);
}
printf("Share memory is now: \n");
for(int i=0; i<numArgc; i++)
{
memory[i]=arrSpace[i];
}
printMemory(memory, numArgc);
printf("Beginning fork process");
for(childId; childId <= numArgc; childId++)
{
pid = fork(); //creates new process
if(pid < 0)
{
printf("There was an error during fork process");
return (0);
}
else if(pid == 0)
{
ChildProcess(memory, numArgc, childId);
exit(0);
}
}
ParentProcess(memory, childPID, numArgc, memoryId, status);
return (0);
}
shmget returns -1 because try variable is undefined and the permission 07546 is invalid.Please pass appropriate permission for the memory segment.
#define MEMORY_SIZE 20 //size of memory segment
memoryId=shmget(IPC_PRIVATE, MEMORY_SIZE , IPC_CREAT | 0666); //create shared
printf("%d \n", memoryId);