inter process communication using shared memory(mmap) and semaphores - c

I am trying to improvise a program I had written for single producer multiple consumer multi threading using counting semaphores. I want to implement inter process communication using shared memory (mmap() system call). I want to use anonymous mapping with no backing file.
This is the structure I want to share between the parent and its multiple child processes.
typedef struct Buffer{
char **Tuples;
sem_t buf_mutex,empty_count,fill_count;
} Buffer;
Buffer buffer[100];
The parent process is the mapper() function which does produces something and puts it in buffer[i], based on some inputs. The child processes go to reducer() function which consumes what is put in its buffer[j]. Each reducer or child process should have access to its buffer. The child processes are forked() in the main function and then the parent process control goes to mapper(). I have initialized the synchronization primitives to be process shared.
Is my main() method the correct way of doing it ? I am also getting type casting errors for return value of mmap(), which is a pointer, but I am not sure how to handle it and then use it. I also think malloc() should not be used in line 47 for allocating space to tuples but instead mmap() itself should be used. Can anyone please help ?
This is my program -
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/mman.h>
typedef struct Buffer{
char **Tuples;
// int count;
sem_t buf_mutex,empty_count,fill_count;
} Buffer;
Buffer buffer[100];
int numOfSlots;
int numOfReducers;
void mapper(){
//Synchronization primitives (counting semaphores) used for synchronization
//Produce something and put it in buffer[i]
}
void reducer(long b){
//Synchronization primitives (counting semaphores) for synchronization
//Consume from buffer[b]
}
int main (int argc, char *argv[]){
if(argc != 3) {
if(argc < 3)
printf("Insufficient arguments passed\n");
else
printf("Too many arguments passed\n");
return 1;
}
int i;
long r;
numOfSlots = atoi(argv[1]);
numOfReducers = atoi(argv[2]);
for(i=0; i<numOfReducers; i++){
buffer[i] = (struct Buffer *) mmap(NULL, sizeof(buffer[i]), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (buffer[i] == MAP_FAILED)
errExit("mmap");
buffer[i].Tuples = malloc(numOfSlots * sizeof(char *));
sem_init(&buffer[i].buf_mutex, 1, 1);
sem_init(&buffer[i].fill_count, 1, 0);
sem_init(&buffer[i].empty_count, 1, numOfSlots);
}
for(r=0;r<numOfReducers;r++){ // loop will run n times (n=5)
if(fork() == 0){
printf("[son] pid %d from [parent] pid %d\n",getpid(),getppid());
Reducer(r);
exit(0);
}
}
mapper();
for(r=0;r<numOfReducers;r++) // loop will run n times (n=5)
wait(NULL);
}
These are the links I am trying to follow -
https://computing.llnl.gov/tutorials/pthreads/man/pthread_mutexattr_init.txt
https://github.com/bradfa/tlpi-dist/blob/master/mmap/anon_mmap.c
Thanks,
Harrish

After researching on the net. I came up with this solution which works.
One more thing I learnt is char *var="hello" is stored in read only memory in the text segment, which means the child processes can also access it. So strcpy() would be a better option for anything else.
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <string.h>
typedef struct Buffer{
char **Tuples;
// int count;
sem_t buf_mutex,empty_count,fill_count;
int inSlotIndex;
int outSlotIndex;
} Buffer;
Buffer *buffer;
int numOfSlots;
int numOfReducers;
int *done;
void mapper(){
//Synchronization primitives (counting semaphores) used for synchronization
//read continuously from a file, produce something and put it in buffer[i]
//Here is an example
char *temp = "trail";
sem_wait(&buffer[1].empty_count);
sem_wait(&buffer[1].buf_mutex);
// Use strcpy() for anything other than string literal
buffer[1].Tuples[0] = temp;
buffer[1].inSlotIndex = 3;
buffer[1].outSlotIndex = 4;
sem_post(&buffer[1].buf_mutex);
sem_post(&buffer[1].fill_count);
*done = 1;
}
void reducer(long tid, Buffer *buffer, int *done){
//Synchronization primitives (counting semaphores) used for synchronization
//Consume from buffer[b]
sem_wait(&buffer[tid].fill_count);
sem_wait(&buffer[tid].buf_mutex);
printf("%s\n", buffer[tid].Tuples[0]);
printf("%d\n", buffer[tid].inSlotIndex);
printf("%d\n", buffer[tid].outSlotIndex);
sem_post(&buffer[tid].buf_mutex);
sem_post(&buffer[tid].empty_count);
if(*done == 1)
printf("DONE\n");
}
int main (int argc, char *argv[])
{
if(argc != 3) {
if(argc < 3)
printf("Insufficient arguments passed\n");
else
printf("Too many arguments passed\n");
return 1;
}
srand(time(NULL));
int i, j;
long r;
char *temp;
numOfSlots = atoi(argv[1]);
numOfReducers = atoi(argv[2]);
buffer = (struct Buffer *)mmap(NULL, numOfReducers * sizeof(struct Buffer), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if(buffer == MAP_FAILED){
printf("EXITING");
exit(EXIT_FAILURE);
}
done = (int *)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (done == MAP_FAILED){
printf("exiting\n");
}
*done = 0;
for(i=0; i<numOfReducers; i++){
buffer[i].Tuples = mmap(NULL, numOfSlots * sizeof(char *), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if(buffer[i].Tuples == MAP_FAILED){
printf("EXITING");
exit(EXIT_FAILURE);
}
for(j=0; j<numOfSlots; j++){
temp = (char *)mmap(NULL, 30 * sizeof(char), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
temp = strcpy(temp, "");
buffer[i].Tuples[j] = temp;
}
sem_init(&buffer[i].buf_mutex, 1, 1);
sem_init(&buffer[i].fill_count, 1, 0);
sem_init(&buffer[i].empty_count, 1, numOfSlots);
}
for(r=0;r<numOfReducers;r++){ // loop will run n times (n=5)
if(fork() == 0){
printf("[son] pid %d from [parent] pid %d\n",getpid(),getppid());
reducer(r, buffer, done);
exit(0);
}
}
mapper();
for(r=0;r<numOfReducers;r++) // loop will run n times (n=5)
wait(NULL);
}

Related

Segmentation fault without even running the first line of code [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 9 months ago.
Improve this question
As you can see in the code I've added printfs everywhere for debugging and have numbered them. I have tried both repl.it and GCC(on gcc it even compiles and everything but when run, it prints the statement that asks for a user input and scans then fails) on ubuntu but both Show segmentation fault without even printing the first printf which is a "1". the code initializes an array in a parent function, sends the array to a child function, then the child prints it. I have to calculate the sum of all the elements in the mentioned array, send it back to the parent, and let the p print it too, but can't even do that if I can't check the functionality of this code
any thoughts?
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sysexits.h>
#include <assert.h>
#include <time.h>
#include <sys/wait.h>
int main() {
printf("\n1\n");
int size;
sem_t *sem1, *sem2, *sem3;
mode_t perms = S_IRUSR | S_IWUSR;
int shmflags = O_CREAT | O_RDWR | O_NONBLOCK;
int semflags = O_CREAT | O_EXCL;
srand(time(NULL));
sem_t *sem = sem_open("/sem1", semflags, perms, 1);
if (sem == SEM_FAILED) {
printf("semaphore_open error \n");
exit(EXIT_SUCCESS);
}
printf("\n2\n");
pid_t pid = fork();
if (pid > 0) {//parent
printf("enter the size of array\n");
scanf("%d", &size);
int array[size];
for (int i = 0; i < size; i++) {
array[i] = rand() % 1001;
}
char str[512];
int i = 0;
int index = 0;
for (i = 0; i < size; i++) {
index += sprintf(&str[index], "%d,", array[i]);
}
printf("\n3\n");
size_t len = strlen(str);
int fd = shm_open("/shmem", shmflags, perms);
if (fd == -1) {
printf("shm_open error \n");
exit(EXIT_SUCCESS);
}
if (ftruncate(fd, len) == -1) {
printf("ftruncate error \n");
exit(EXIT_SUCCESS);
}
char *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
printf("mmap error \n");
exit(EXIT_SUCCESS);
}
if (close(fd) == -1) {
printf("fd close error \n");
exit(EXIT_SUCCESS);
}
sem_wait(sem);
memcpy(addr, str, strlen(str));
sem_post(sem);
wait(NULL);
} else { //child
struct stat sb;
printf("\n4\n");
int fd = shm_open("/shmem", O_RDONLY, 0);
if (fstat(fd, &sb) == -1) {
printf("fstat error \n");
exit(EXIT_SUCCESS);
}
char *addr = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
printf("mmap error \n");
exit(EXIT_SUCCESS);
}
if (close(fd) == -1) {
printf("fd close error \n");
exit(EXIT_SUCCESS);
}
printf("\n5\n");
sem_wait(sem);
puts(addr);
sem_post(sem);
if (shm_unlink("/shmem") == -1) {
printf("unlink error \n");
exit(EXIT_SUCCESS);
}
if (sem_unlink("/sem1") == -1) {
printf("unlink error \n");
exit(EXIT_SUCCESS);
}
}
return 0;
}
Here are a few good candidates for undefined behavior:
scanf("%d", &size);
int array[size];
for (int i = 0; i < size; i++) {
array[i] = rand() % 1001;
}
If size is too large, say greater than a few millions, the array allocated with automatic storage will likely cause a stack overflow.
char str[512];
int i = 0;
int index = 0;
for (i = 0; i < size; i++) {
index += sprintf(&str[index], "%d,", array[i]);
}
If size entered by the user is larger than 128, the code converting the array to a string will likely cause a buffer overflow causing undefined behavior.
In the child process:
puts(addr);
addr points to the memory mapped file contents. This file does not contain a null terminator, hence if by chance its size is a multiple of the page size, the memory mapped block will not contain a null terminator and puts(addr) will read beyond the end of the block, causing undefined behavior.
Note that none of the above may cause the process to fail before the first printf call.

IPC through shared memory and pipe gives segmentation fault: 11 in C

I am trying to share a file between parent and child processes. Parent sends the file via a pipe and child write that lines into shared memory so that parent can read and print out the file via shared memory. However, I am getting segmentation fault: 11. Besides, I did something similar like the code below, but that time I could not get the correct content and even I was getting different results at each call.
I am not sure about increasing the pointer part. But, it is better to have an extra eye on the code.
Edit: I corrected char* to char[] and segmentation fault is now gone. However, I get different results at each run, some extra characters are seen in output.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#define SHM_NAME_1 "Child 1"
int main(){
pid_t pid;
FILE *file;
char *infile = "in.txt";
pid = fork();
if(pid < 0){
fprintf(stderr, "Fork failed\n");
return 1;
}
if(pid > 0){ // parent
file = fopen(infile, "r");
if(file == 0){
fprintf(stderr, "File failed\n");
return 1;
}
// close read end of pipe
mknod("FIFO", S_IFIFO | 0666, 0);
int fd = open("FIFO", O_WRONLY);
char str[300];
while(fgets(str, sizeof(str), file) > 0)
{
// write all lines of file
write(fd, str, strlen(str));
}
// close file and pipe
close(fd);
fclose(file);
// wait for child to write to shared memory
wait(NULL);
// open shared segment
int shm_first = shm_open(SHM_NAME_1, O_RDONLY, 0666);
if (shm_first == -1) {
fprintf(stderr, "Failed: Shared Memory 1");
exit(-1);
}
// create memory pointer
void *ptr = mmap(0,4096, PROT_READ, MAP_SHARED, shm_first, 0);
if (ptr == MAP_FAILED) {
printf("Map failed 1\n");
return -1;
}
// print out result and unlibk shared segment
fprintf(stdout, "Normal input: \n%s\n", ptr);
shm_unlink(SHM_NAME_1);
} else { // child
// create the shared segment for the first time
int shm_child_1 = shm_open(SHM_NAME_1, O_CREAT | O_RDWR, 0666);
// configure the size of the shared memory segment
ftruncate(shm_child_1,4096);
// map the pointer to the segment
void *ptr_child_1 = mmap(0,4096, PROT_READ | PROT_WRITE, MAP_SHARED, shm_child_1, 0);
if (ptr_child_1 == MAP_FAILED)
{
printf("Map failed in first child\n");
return -1;
}
mknod("FIFO", S_IFIFO | 0666, 0);
int fd = open("FIFO", O_RDONLY);
int num;
char s[300];
while((num = read(fd, s, sizeof(s)))> 0)
{
sprintf(ptr_child_1, "%s", s);
ptr_child_1 += num;
}
close(fd);
exit(0);
}
return 0;
}
One quick observation.
In the following code, you have a char pointer that is not initialized to point to anything. Which causes fgets to copy what it reads from file to some arbitrary place in memory.
char *str;
while(fgets(str, 100, file) > 0)
Now that the buffer issues are resolved, there is also an issue with the braces in the following expression
while((num = read(fd, s, sizeof(s)) > 0))
num is going to be 1 or 0 rather than the number of bytes read or 0 for eof. This should be
while((num = read(fd, s, sizeof(s))) > 0)
Once you have the number of bytes read, you need to zero terminate the buffer. Because you are using sprintf which expects the argument for %s to be a zero terminated string.
while((num = read(fd, s, sizeof(s)))> 0)
{
s[num] = '\0'; // Terminate the string to the number of bytes read
sprintf(ptr_child_1, "%s", s);
ptr_child_1 += num;
}

Getting Zero in out as value of shared memory variable

I have a parent program which will fork the following child program and increment, display, decrement and display the variable 'test' (initially 0) 15 times. I tried to run it a lot of times and see what output I get after every few lines, however I'm not able to know how my 'test' variable is showing only zero, 15 times.
//Include required preprocessors
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#define SHARED_MEM 1024 //shared memory size
int main(void)
{
/* The child process' new program. This program replaces the parent's */
/* program when 'fork()' is called */
printf("Process[%d]: child in execution ... \n",getpid());
int MAX = 15;
int shmID, shmID2;
key_t key = 1234, key2 = 2345;
int *test, *counter;
shmID = shmget(key, SHARED_MEM, 0666);
printf("\nShmID: %d", shmID);
shmID2 = shmget(key2, SHARED_MEM, 0666);
printf("\nshmID2: %d", shmID2);
test = (int *) shmat(shmID, 0, 0);
counter = (int *) shmat(shmID2, 0, 0);
printf("\ntEST before assignment: %d", *test);
printf("\nCounter: %d", *counter);
*test = 0;
*counter = 1;
printf("\ntest: %d", *test);
printf("\nCounter%d", *counter);
printf("\nAlmost there...");
if (*counter == 1){
for(int i=0; i < MAX; i++){
printf("\MAX: %d", MAX);
printf("%d", *test);
*test++;
}
*counter++; //to enter second condition of second child process
printf("\nCounter: %d", counter);
}
else if(*counter == 2){
for(int j = 0; j < MAX; j++){
printf("%d", *test);
*test++;
}
*counter--;
}
sleep(1);
printf("Process[%d]: child terminating ... \n", getpid());
shmdt(test);
shmdt(counter);
return 0;
}
I can see several things.
Independently of how is code structured, I'd check if there's an error in shmget and shmat:
I'd change
shmID = shmget(key, SHARED_MEM, 0666)
shmID2 = shmget(key2, SHARED_MEM, 0666);
by
if ( (shmID = shmget(key, SHARED_MEM, 0666)) < 0)
{
perror("shmget");
exit(1);
}
if ( (shmID2 = shmget(key2, SHARED_MEM, 0666) < 0)
{
perror("shmat");
exit(1);
}
Note that you're creating SHM with 0666 privileges but without IPC_CREAT | IPC_EXCL.
I recommend you create first time with IPC_CREAT | IPC_EXCL | 0666 flags.
In the same way that 1st point, I'll check also problems with shmat:
See example for test. Should be the same for counter.
if ((test = (int *) shmat(shmID, 0, 0)) == -1)
{
perror("shmat");
exit(1);
}
You can check in cli if there's something wrong with shm, for instance, is already created, using command ipcs to check or ipcrm shm to delete and re-initialize:
ipcs shm | grep [your_shm_key or shmid]

One Process per Client Server using Shared Memory in C

I am creating an "One Process per Client" server using the TCP protocol for academic purpose.
I use a global struct like the one bellow:
struct keyvalue
{
char a[4096];
char b[4096];
}data[1000];
I use fork() to create a child for each client.
I know that each child sees this struct as an exact copy of the parent process however if a child makes a change it is not visible to the other children and this is my goal.
I searched in google for hours and the only proper solution i found is mmap()
Bellow I present how i tried to solve this task:
int main ( int argc, char *argv[])
{
for(int c = 0; c < 1000 ; c++)
{
data[c] = mmap(NULL, sizeof(data[c]), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
}
.
.
.
return 0;
}
However I think that I haven't understand properly the use of this function and the documentation didn't help for this project.
It would be great if someone explained to me the exact way to use this function for my project.
EDIT:
This global struct is used by two global function:
void put(char *key, char *value)
{
.
.
.
strcpy(data[lp].keys,key);
strcpy(data[lp].values,value);
.
.
.
}
Thank you in behave and sorry for my bad English.
You can use the following piece of code to create an array of structs that is shared across multiple forked processes.
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define MAX_LEN 10000
struct region {
int len;
char buf[MAX_LEN];
};
int fd;
int main(void){
//Create shared memory
fd = shm_open("/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
printf("Error: shm_open\n");
//Expand to meet the desirable size
if (ftruncate(fd, MAX_LEN*sizeof(struct region)) == -1)
printf("Error: ftruncate\n");
pid_t pid = fork();
if (pid == 0){
struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
printf("Error\n");
memset(ptr, 0, 50*sizeof(struct region));
usleep(1500000);
ptr[33].len = 42;
}else if (pid > 0){
struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
printf("Error\n");
usleep(1000000);
printf("Value before: %d\n", ptr[33].len);
usleep(1000000);
printf("Value after: %d\n", ptr[33].len);
}else{
printf("Error: fork\n");
}
shm_unlink("/myregion");
return 0;
}
Compilation: gcc -o shmem_test shmem_test.c -lrt
EDIT: If you can't use shm_open, alternatively you can do the following in your main function:
int main(void){
struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED,-1,0);
pid_t pid = fork();
if (pid == 0){
usleep(1500000);
ptr[33].len = 42;
}else if (pid > 0){
usleep(1000000);
printf("Value before: %d\n", ptr[33].len);
usleep(1000000);
printf("Value after: %d\n", ptr[33].len);
}else{
printf("Error: fork\n");
}
return 0;
}
The difference between the two, is that shm_open creates a named shared memory, which means that different processes in different executables can map this memory, given that they have the struct region definition. In the second case this cannot be done, i.e the shared memory is anonymous.

What alternatives I have against sleep() to synchronize transfer between parent and child process?

I'm facing a synchronization problem, the problem I'm trying to solve involves sending string from parent to child, reversing it and sending it back to child ( using shared memory ).
However to make sure child is waiting for parent I'm using sleep(3) to give 3 seconds to parent process to enter string, however this is limiting my programs efficiency, I don't want to force user to wait for 3 seconds.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/wait.h> /* Needed for the wait function */
#include <unistd.h> /* needed for the fork function */
#include <string.h> /* needed for the strcat function */
#define SHMSIZE 27
int main() {
int shmid;
char *shm;
if(fork() == 0) {
sleep(3);
shmid = shmget(29009, SHMSIZE, 0);
shm = shmat(shmid, 0, 0);
printf ("Child : Reading %s \n",shm) ;
int len=strlen(shm);
char rev[100],temp;
int i = 0;
int j = strlen(shm) - 2;
while (i < j) {
temp = shm[i];
shm[i] = shm[j];
shm[j] = temp;
i++;
j--;
}
shmdt(shm);
}else {
shmid = shmget(29009, SHMSIZE, 0666 | IPC_CREAT);
shm = shmat(shmid, 0, 0);
printf("Parent : Enter String \n ");
char *s = (char *) shm;
*s = '\0';
char a[100];
fgets(a,100,stdin);
strcat(s,a);
printf ("Parent: sending %s \n",shm);
sleep(3);
printf("Parent: receiving %s" ,shm);
shmdt(shm);
}
return 0;
}
Question:
How could this be implemented in a better way, so that the program is more efficient?
I would suggest using semaphores, this is not a case where you use 'sleep':
http://man7.org/linux/man-pages/man7/sem_overview.7.html
You can use them like in this example:
http://www.csc.villanova.edu/~mdamian/threads/posixsem.html
You cannot know for sure that it will not take more than 3 seconds, so sleep is a realy bad choice. So, it goes something like this:
#include <stdio.h>
#include <semaphore.h>
int main(void)
{
sem_t *sem = mmap(0, sizeof(sem_t), PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_ANONYMOUS, -1, 0);
sem_init(sem, 1, 1);
if(fork() == 0) {
printf("Child: Waiting to acquire semaphore\n");
sem_wait(sem);
printf("Child acquires lock\n");
/* do whatever you want then relese*/
sem_post(sem);
} else {
printf("Parent: Waiting to acquire semaphore\n");
sem_wait(sem);
printf("Parent acquires lock\n");
/* do whatever you want then relese*/
sem_post(sem);
}
sem_destroy(sem);
return 0;
}
Oh and if you want it parent to be followed by child always (or the other way around), you can use two semaphores, and initialize them accordingly(with 1 and 0, or 0 and 1).
sem_wait(sem1);
printf("Parent acquires lock\n");
/* do whatever you want then relese*/
sem_post(sem2);
/* Other things will be happening here */
sem_wait(sem2);
printf("Child acquires lock\n");
/* do whatever you want then relese*/
sem_post(sem1);
Edit
If you do not have to use shared memory, it would be better to do the communication with sockets.
Thanks to amazing StackOverflow community for coming to my rescue! I have resolved solved the issue using semaphores! I'm sharing my final code so it can be of use for anyone who gets struck in a situation like mine!
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/wait.h> /* Needed for the wait function */
#include <unistd.h> /* needed for the fork function */
#include <string.h> /* needed for the strcat function */
#include <semaphore.h>
#include <sys/mman.h>
#include<fcntl.h>
#include<stdlib.h>
#define SHMSIZE 27
typedef struct {
sem_t one;
sem_t two;
} SemPair;
int main() {
int shm = shm_open("/test", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
ftruncate(shm, sizeof(sem_t));
SemPair *sem = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0);
sem_init(&(sem->one), 1, 0);
sem_init(&(sem->two), 1, 0);
int shmid;
char *shmz;
if(fork() == 0) {
sem_wait(&(sem->one));
shmid = shmget(29009, SHMSIZE, 0);
shmz = shmat(shmid, 0, 0);
printf ("Child : Reading %s \n",shmz) ;
int len=strlen(shmz);
char rev[100],temp;
int i = 0;
int j = strlen(shmz) - 2;
while (i < j) {
temp = shmz[i];
shmz[i] = shmz[j];
shmz[j] = temp;
i++;
j--;
}
shmdt(shmz);
sem_post(&(sem->two));
}
else {
shmid = shmget(29009, SHMSIZE, 0666 | IPC_CREAT);
shmz = shmat(shmid, 0, 0);
printf("Parent : Enter String \n ");
char *s = (char *) shmz;
*s = '\0';
char a[100];
fgets(a,100,stdin);
strcat(s,a);
printf ("Parent: sending %s \n",shmz);
sem_post(&(sem->one));
sem_wait(&(sem->two));
printf("Parent: receiving %s" ,shmz);
shmdt(shmz);
}
return 0;
}

Resources