Related
I created a for loop in C that is responsible for creating a given amount of processes. There is a section in the for loop (pid > 0) for the parent, and a section for the child (pid == 0). The wait() function call is after the loop finishes, but I am having a problem where some of the child processes start executing their fprintf statements while the parent is still running the for loop. How can I make sure all of the children do NOT start running until the parent has gone through the for loop and finished all fprintf statements in order?
> ./a.out 5 process 1
*[EXPECTED]*
Process 0 creating process 1...
Process 0 creating process 2...
Process 0 creating process 3...
Process 0 creating process 4...
Process 0 creating process 5...
Process 1 beginning...
*(SLEEP RANDOM AMOUNT OF TIME)*
Process 1 ending...
Process 2 beginning...
*(SLEEP RANDOM AMOUNT OF TIME)*
Process 2 ending...
Process 3 beginning...
*(SLEEP RANDOM AMOUNT OF TIME)*
Process 3 ending...
Process 4 beginning...
*(SLEEP RANDOM AMOUNT OF TIME)*
Process 4 ending...
Process 5 beginning...
*(SLEEP RANDOM AMOUNT OF TIME)*
Process 5 ending...```
```*[ACTUAL RESULT]*
Process 0 creating process 1...
Process 1 beginning...
Process 0 creating process 2...
Process 2 beginning...
Process 0 creating process 3...
Process 0 creating process 4...
Process 0 creating process 5...
Process 5 beginning...
Process 3 beginning...
Process 4 beginning...
*(SLEEP RANDOM AMOUNT OF TIME)*
Process 1 ending...
Process 2 ending...
Process 5 ending...
Process 3 ending...
Process 4 ending...`
The output is never not the same, and the child processes often begin in a random order in between each parent process loop iteration.
Here is my code:
main.c:
/*
* Write a program that takes three arguments:
* the number of “things” (between 1 and 256),
* a word: either “thread” or “process, and
* a “pattern number” (1-2 only).
*/
#include "functions.c"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
// USE STDERR FOR PRINTING
// fprintf(stderr, "This is process %d \n", getpid());
// extern set_pattern
typedef struct {
int number;
pid_t pid;
} process;
typedef struct {
int number;
pthread_t tid;
} thread;
int main(int argc, char *argv[]) {
setbuf(stdout, NULL);
// Check for correct amount of paramters
if (argc != 4) {
help_and_exit(argv[0]);
}
// Parse parameters and check for errors
// Set size
int size;
set_size(argv, &size);
// Set type (thread or process)
exec_t type;
set_choice(argv, &type);
// Set pattern
int pattern;
set_pattern(argv, &pattern);
// printf("Size is %d, choice is %d, and pattern is %d\n", size, type,
// pattern);
if (pattern == 1) {
if (type == Process) {
// process processes[size];
pid_t alpha_process = getpid();
int process_number = 0;
pid_t pids[size];
int n = size;
int flag = 0;
for (int i = 0; i < n; i++) {
fflush(stdout);
if ((pids[i] = fork()) < 0) {
perror("fork");
} else if (pids[i] == 0) {
fprintf(stderr, "Process %d beginning...\n", i + 1);
sleep(rand() % 5);
fflush(stdout);
fprintf(stderr, "Process %d ending...\n", i + 1);
exit(0);
} else if (pids[i] > 0) {
fprintf(stderr, "Process %d creating process %d...\n", i - i, i + 1);
}
}
int counter = 0;
while (counter < n) {
wait(NULL);
counter++;
}
}
}
return 0;
}
functions.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
typedef enum { Thread, Process } exec_t;
void help_and_exit(char *name) {
fprintf(stderr,
"usage: %s <number of things> {thread | process} <pattern number>\n",
name);
exit(-1);
}
void set_size(char *argv[], int *size) {
if (sscanf(argv[1], "%d", size) == 0) {
fprintf(stderr, "First parameter must be an integer. Recieved: '%s'\n",
argv[1]);
help_and_exit(argv[0]);
}
if (*size > 256 || *size < 1) {
fprintf(stderr, "Number of things must be between 1-256!\n");
help_and_exit(argv[0]);
}
}
void set_choice(char *argv[], exec_t *type) {
char choice[8];
if (sscanf(argv[2], "%s", choice) == 0) {
fprintf(stderr, "Second parameter must be a string. Recieved: '%s'\n",
argv[2]);
help_and_exit(argv[0]);
}
if (strcmp(choice, "thread") != 0 && strcmp(choice, "process") != 0) {
fprintf(stderr, "Second parameter must be either 'thread' or 'process'\n");
help_and_exit(argv[0]);
} else if (strcmp(choice, "thread") == 0) {
*type = Thread;
} else {
*type = Process;
}
}
void set_pattern(char *argv[], int *pattern) {
if (sscanf(argv[3], "%d", pattern) == 0) {
fprintf(stderr, "Third parameter must be an integer. Recieved: '%s'\n",
argv[3]);
help_and_exit(argv[0]);
}
if (*pattern != 1 && *pattern != 2) {
fprintf(stderr, "Pattern number must be either 1 or 2!\n");
help_and_exit(argv[0]);
}
}
Put each child on pause() and have the parent wake them up after the loop by sending a signal. (Credit to DYZ for the answer)
#include "functions.c"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
//snip-snip...
int cont;
void handleContinueSignal(int sig) { cont = 1; }
int main(int argc, char *argv[]) {
// snip-snip...
if (pattern == 1) {
if (type == Process) {
// snip-snip...
for (int i = 0; i < n; i++) {
fflush(stdout);
if ((pids[i] = fork()) < 0) {
perror("fork");
} else if (pids[i] == 0) {
signal(SIGCONT, handleContinueSignal);
pause();
fprintf(stderr, "Process %d beginning...\n", i + 1);
sleep(rand() % 5);
fflush(stdout);
fprintf(stderr, "Process %d ending...\n", i + 1);
exit(0);
} else if (pids[i] > 0) {
fprintf(stderr, "Process %d creating process %d...\n", i - i, i + 1);
}
}
int counter = 0;
while (counter < n) {
kill(pids[counter], SIGCONT);
wait(NULL);
counter++;
}
}
}
return 0;
}
I posted the issue with fork() and pipe(), but later I saw that the problem was only in pipe().
So I'm removing fork() code from here.
Problem: Writing in pipe(), and reading from pipe() but never reach the EOF condition in loops
Here is a simplification code of the problem:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int fd[2];
int main() {
if(pipe(fd) == 0) {
printf("Pipe is Open\n");
}
for(int i = 0; i < 5; i++) {
close(fd[1]);
write(fd[0], &i, sizeof(int));
close(fd[0]);
}
for(int i = 0; i < 5; i++) {
int value;
close(fd[0]);
read(fd[1], &value, sizeof(int));
close(fd[1]);
printf("%d\n", value);
}
return 0;
}
Output:
Pipe is Open
4
4
4
4
4
Despite wanting to read in a loop multiple times, you close the file descriptor immediately after the first read, so that subsequent reads must fail; in addition, you forget to check the reads' return value for error and so use the unchanged value from the previous loop cycle.
Had to use <fcntl.h> to work properly
<fcntl.h> is a file control removed the need to close the pipe off my hands in order for it to reach EOF
if (fcntl(fd[0], F_SETFL, O_NONBLOCK) < 0)
exit(-1);
Where fd[0] is the pipe created
Without the fcntl() the code never hit the EOF condition
The implementations below, unlike the previous code, the close() has been removed and the fcntl() has been added to handle this, giving the output as desired to read values inside a pipe in a loop until reaching EOF.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int fd[2];
int main() {
if(pipe(fd) == 0) {
printf("Pipe is Open\n");
}
if (fcntl(fd[0], F_SETFL, O_NONBLOCK) < 0)
exit(-1);
for(int i = 0; i < 5; i++) {
write(fd[1], &i, sizeof(int));
}
int status;
while(1) {
int value;
status = read(fd[0], &value, sizeof(int));
printf("status: %d\n", status);
if(status > 0) {
printf("%d\n", value);
} else {
// END of FILE
printf("\nEOF\n");
break;
}
}
return 0;
}
OUTPUT:
Pipe is Open
status: 4
0
status: 4
1
status: 4
2
status: 4
3
status: 4
4
status: -1
EOF
I need help with my c program, I have most of it done but it has some issues.
The program is about ** Exploring Synchronization Among Processes and Threads.**
You are given three (3) processes in one program that work together to solve a producer consumer problem:
2 processes are “producers” and each process produces its own type of product in a continuous loop. That is, one product type produced by one producer and a different product type by the other producer.
One Process is a “consumer” of products and consist of five (5) threads:
1 thread is a ‘distributor’ thread
two (2) threads consume one type of product (ex. consumes only product type 1)
two (2) threads consume a second type of product (ex. consumes only product type 2).
The consumer process contains two (2) product storage buffers, each comprised of a fixed number of slots. The number of slots in the buffers are to be different (one has more slots than
the other). You choose and specify the number of slots in each buffer as a definition in your
program solution
Communication between the producer processes and the consumer process is to be through a
single “pipe”. This single, shared pipe is used to communicate between each producer process
and the consumer process. Each producer process writes into this pipe the product to be
consumed by the consumer process.
Final program delivery: completion of the product consumer threads, output file design and
write functions; sample data runs with output files
I have most of it done but it has some issues.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <stdbool.h>
#include <fcntl.h>
#include <pthread.h>
#define BUFFER_SIZE1 20
#define BUFFER_SIZE2 30
typedef struct
{
int count;
int productType;
} product;
int count = 0;
int fd[2];
pthread_mutex_t lock;
pthread_cond_t cond;
typedef struct
{
product *values;
int head;
int tail;
int numEntries;
int size;
} queue;
queue q1;
queue q2;
void producer(int args);
void *consumer(void *args);
void *distributor(void *args);
void initQ(queue *q, int size);
bool QEmpty(queue *q);
bool QFull(queue *q);
bool put(queue *q, product prod);
product get(queue *q);
// https://www.youtube.com/watch?v=l6zkaJFjUbM
// https://www.geeksforgeeks.org/multithreading-c-2/
int main(int argc, char const *argv[])
{
// Creating 5 threads 4 consumer and 1 distributor
pthread_t th[5];
// Creating our pipe, fd[0] is read end, fd[1] is write end
if (pipe(fd) == -1)
{
perror("error creating pipe");
exit(1);
}
// Initializing both buffers
initQ(&q1, BUFFER_SIZE1);
initQ(&q2, BUFFER_SIZE2);
int pid1;
int pid2;
int consId1 = 1;
int consId2 = 2;
// Initializing lock
pthread_mutex_init(&lock, NULL);
// Initialziing condition variables
pthread_cond_init(&cond, NULL);
// Create first producer process using fork(), child process 1
if (pid1 = fork() == 0)
{
producer(1);
}
// Create second prodcuer process using fork(), child process 2
else if (pid2 = fork() == 0)
{
producer(2);
}
// Create distrubtor and consumer threads, parent process
else
{
// Creating 4 threads using for loop and pthread_create
for (int i = 0; i < 4; i++)
{
// 2 consumer threads for product type 1
if (i == 1 || i == 2)
{
if (pthread_create(&th[i], NULL, &consumer, &consId1) != 0)
{
perror("Error creating thread");
}
}
// 2 consumer threads for product type 2
else
{
if (pthread_create(&th[i], NULL, &consumer, &consId2) != 0)
{
perror("Error creating thread");
}
}
}
// use pthread_join to wait for preivous thread to terminate
for (int i = 0; i < 4; i++)
{
if (pthread_join(th[i], NULL) != 0)
{
perror("Error joining thread");
}
}
// Distributor thread
close(fd[1]);
while (1)
{
product prod;
// Using lock and condition variable around crit section to avoid race condition
// pthread_mutex_lock(&lock);
// pthread_cond_wait(&cond, &lock);
// Read from the pipe
read(fd[0], &prod, sizeof(prod));
if (prod.productType == 1)
{
put(&q1, prod);
}
else
{
put(&q2, prod);
}
}
// pthread_cond_signal(&cond);
// pthread_mutex_unlock(&lock);
// Close read end of the pipe
close(fd[0]);
}
return 0;
}
// Creating the producers
void producer(int args)
{
int prodCount = 0;
product prod;
prod.productType = args;
// Close read end of the pipe
close(fd[0]);
while (1)
{
prodCount++;
prod.count = prodCount;
// Send product to the pipe so the consumer can use
write(fd[1], &prod, sizeof(prod));
// Sleep for 0.01 - 0.2 seconds after each loop
int time = (rand() % (200000 - 10000 + 1)) + 10000;
usleep(time);
}
// Close write end of the pipe
close(fd[1]);
}
void *consumer(void *args)
{
int consCount1;
int consCount2;
FILE *fp;
fp = fopen("output.txt", "w");
product prod;
int prodType = *(int *)args;
while (1)
{
if (prodType == 1)
{
get(&q1);
consCount1++;
fprintf("Thread ID: %d\n", prodType);
fprintf(fp, "Product Type: %d\n", prod.productType);
fprintf(fp, "Production Sequence #: %d\n", prod.count);
fprintf(fp, "Consumption Sequence #: %d\n", consCount1);
}
else
{
get(&q2);
consCount2++;
fputs("Thread ID: 2\n", fp);
fprintf(fp, "Product Type: %d\n", prod.productType);
fprintf(fp, "Production Sequence #: %d\n", prod.count);
fprintf(fp, "Consumption Sequence #: %d\n", consCount2);
}
}
fclose(fp);
}
// https://www.youtube.com/watch?v=oyX30WVuEos&t=196s
// Circular buffer
void initQ(queue *q, int size)
{
q->size = size;
q->values = malloc(sizeof(product) * q->size);
q->numEntries = 0;
q->head = NULL;
q->tail = NULL;
}
// Checks if the queue is empty
bool QEmpty(queue *q)
{
return (q->numEntries == 0);
}
// Checks if the queue is full
bool QFull(queue *q)
{
return (q->numEntries == q->size);
}
// Used for adding products to the queue
bool put(queue *q, product prod)
{
// If the queue is full we can not add to it
if (QFull(q))
{
return false;
}
// Add product to the end of the queue
q->values[q->tail] = prod;
q->numEntries++;
// Move index of the tail
q->tail = (q->tail + 1);
// If index goes out of bounds set back to 0
if (q->tail >= q->size)
{
q->tail = 0;
}
return true;
}
// Used for removing products for the queue
product get(queue *q)
{
product result;
// If the queue is empty we can not dequeue anymore
if (QEmpty(q))
{
perror("Error on dequeue");
}
// Remove from the head of the queue
result = q->values[q->head];
q->head = (q->head + 1) & q->size;
q->numEntries--;
return result;
}
I suggest to revise the code to make it more readable since now it's quite hard to understand.
Here I point out some issues of your code that lead to errors:
if condition if (pidN = fork() == 0) {...}
you should fork() first and then check the pid:
int pidN = fork();
if (pidN == 0) {...}
fprintf() function fprintf("Thread ID: %d\n", prodType);
either write the function fputs or fprintf:
fputs("Thread ID: \n", fp);
or
fprintf(fp, "Thread ID: %d\n", prod.productType);
Parameter of the fprintf() function: pay attention to the variable you're passing since prodType does not exist.
thank you for taking your time to read this.
I'm trying to implement a semaphore through a file using C on a linux machine.
I have two process that I must synchronize, one has all the consonants of a file stored in an array, the other has all the vowels.
I've arranged these arrays so that if I alternate between them, I can reconstruct the original file and paste it in another file.
The issue now is making these two process alternate.
This exercise in particular wants me to implement a semaphore using a 3rd file.
What I've done is use the first byte of this file as a semaphore, lot loop one process until the other is finished.
I've tested with long sleep()s and yes, if these processes do alternate, the output file is exactly how I want it, but with that said, my current implementation of a semaphore seems not to be working.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <fcntl.h>
int main (){
int child1=0, child2=0, fd, fd2, fs, i=0, i2=0;
int count=0, count2=0;
char buf1[20], buf2[20], a, b, con='1', vow='0', check1, check2;
fd=open("text", O_RDONLY);
fd2=open("text2", O_CREAT|O_RDWR|O_TRUNC,0777);
fs=open("semaphore", O_RDWR, 0777);
if (fork()==0)
child1=1;
else {
if (fork()==0)
child2=1;
}
//access vowel child
if (child1){
printf("I'm the first child\n");
while ((read(fd,&a,1))==1){
if (a=='a' || a=='e' || a=='i' || a=='o' || a=='u')
buf1[count]=a;
count++;
}
printf("count: %d\n", count);
//vowels are now into buf1
//wait for the brother to do the same
sleep(2);
for (i; i<=count+1; i++){
if (buf1[i]!='\0'){
printf("%c\n", buf1[i]);
a=buf1[i];
write(fd2,&a,1);
}
lseek(fs,0,SEEK_SET);
write(fs,&con,1);//tell the semaphore it's the consonant's turn (1)
while(check1=='1'){
lseek(fs,0,SEEK_SET);
read(fs,&a,1);
check1=a;
sleep(1);
} //get stuck until it's somebody's else turn
}
}
//access consonant child
else if (child2){
sleep(1);
lseek(fd,0,SEEK_SET);
printf ("I'm the second child\n");
while ((read(fd,&a,1))==1){
if (a=='a' || a=='e' || a=='i' || a=='o' || a=='u')
;
else
buf2[count2]=a;
count2++;
}
//resync
sleep(1);
printf("count: %d\n", count2);
//consonants are now into buf1
for (i; i<=count2+1; i++){
lseek(fs,0,SEEK_SET);
if (buf2[i]!='\0'){
printf("%c\n", buf2[i]);
b=buf2[i];
write(fd2,&b,1);
} //wait for vowel
while(check2=='0'){
lseek(fs,0,SEEK_SET);
read(fs,&b,1);
check2=b;
sleep(1);
}
lseek(fs,0,SEEK_SET);
write(fs,&vow,1);//tell the semaphore it's the vowel's turn (0)
}
}
else
printf("I'm the father\n");
sleep(10);
exit(0);
}
The file "text" has "hello world" stored in it. What happens when I execute this code is that what's copy and pasted is "hll wrld eoo". What exactly am I doing wrong with my semaphore?
Basically, you want to implement acquire/release similar to pthread_mutex_t or sem_t.
You need two functions:
acquire to wait for and acquire ownership
release to release ownership and grant it to the "other" process
You're conflating the two operations into one. And, your code doesn't actually do locking properly.
Side note: You are creating "zombie" processes because the father does not do wait on the children.
Here's some refactored code.
I added acquire and release calls to the places where you had your sempahore code (e.g. the second loops for each child). But, you might need them in the first loops as well (which I did not do).
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
void
acquire(int fs,char iam)
{
char own;
while (1) {
lseek(fs,0,SEEK_SET);
read(fs,&own,1);
if (own == iam)
break;
usleep(1);
}
}
void
release(int fs,char iam)
{
char other;
if (iam == 1)
other = 2;
else
other = 1;
lseek(fs,0,SEEK_SET);
write(fs,&other,1);
}
int
main()
{
int child1 = 0,
child2 = 0,
fd,
fd2,
fs,
i = 0,
i2 = 0;
int count = 0,
count2 = 0;
char buf1[20],
buf2[20],
a,
b,
con = '1',
vow = '0',
check1,
check2;
fd = open("text", O_RDONLY);
fd2 = open("text2", O_CREAT | O_RDWR | O_TRUNC, 0777);
fs = open("semaphore", O_RDWR | O_CREAT, 0777);
// initialize semaphore to grant access to one or the other
buf1[0] = 1;
write(fs,buf1,1);
if (fork() == 0)
child1 = 1;
else {
if (fork() == 0)
child2 = 1;
}
// access vowel child
if (child1) {
printf("I'm the first child\n");
while ((read(fd, &a, 1)) == 1) {
if (a == 'a' || a == 'e' || a == 'i' || a == 'o' || a == 'u')
buf1[count] = a;
count++;
}
printf("count: %d\n", count);
// vowels are now into buf1
// wait for the brother to do the same
sleep(2);
for (i; i <= count + 1; i++) {
acquire(fs,1);
if (buf1[i] != '\0') {
printf("%c\n", buf1[i]);
a = buf1[i];
write(fd2, &a, 1);
}
release(fs,1);
}
}
// access consonant child
else if (child2) {
sleep(1);
lseek(fd, 0, SEEK_SET);
printf("I'm the second child\n");
while ((read(fd, &a, 1)) == 1) {
if (a == 'a' || a == 'e' || a == 'i' || a == 'o' || a == 'u');
else
buf2[count2] = a;
count2++;
}
// resync
sleep(1);
printf("count: %d\n", count2);
// consonants are now into buf1
for (i; i <= count2 + 1; i++) {
acquire(fs,2);
if (buf2[i] != '\0') {
printf("%c\n", buf2[i]);
b = buf2[i];
write(fd2, &b, 1);
} // wait for vowel
release(fs,2);
}
}
else {
printf("I'm the father\n");
while (wait(NULL) >= 0);
printf("all done\n");
}
//sleep(10);
exit(0);
}
UPDATE:
The two child processes share a common file position for the semaphore file because the open call is done in the parent.
So, there is a potential race condition between the lseek and the read or write.
There are two ways to solve this:
Have each child open the semaphore file after the fork. Then, they do not share the file position.
Instead of lseek followed by read or write, use pread or pwrite.
Here is the latter:
void
acquire(int fs,char iam)
{
char own;
while (1) {
pread(fs,&own,1,0);
if (own == iam)
break;
usleep(1);
}
}
void
release(int fs,char iam)
{
char other;
if (iam == 1)
other = 2;
else
other = 1;
pwrite(fs,&other,1,0);
}
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().