How To Implement IPC Using Shared Memory - c

I have the following problem to solve:
implement IPC between 3 processes in a way that the first process create the shared memory and then sends a signal to the second and third processes so they can get attached to that shared memory, now make the second process write something to the shared memory and then make it send a signal to the third process so that the third process reads what the second process had written.
this is what I've came up with so far
First_Process.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
struct memory {
char msg[100];
int status, pid1, pid2, pid3;
};
struct memory* shmptr;
int main()
{
// First_Process Process Id
int pid = getpid();
// Key Of The Shared Memory
key_t key = ftok("/tmp", 'a');
// Shared Memory Creation
int shmid = shmget(key, sizeof(struct memory), IPC_CREAT | 0666);
// Attaching First_Process To The Shared Memory
shmptr = (struct memory*)shmat(shmid, NULL, 0);
// Store The First_Process Process Id In The Shared Memory
shmptr->pid1 = pid;
while (1) {
// Waiting For Second_Process And Third_Process To Get Attached To The Shared Memory
while (shmptr->status != 1)
continue;
sleep(1);
// Sending The Notification to Second_Process And Third_Process Using The Kill Command
//kill(shmptr->pid2, SIGUSR1);
//kill(shmptr->pid3, SIGUSR1);
}
// Detaching First_Process From The Shared Memory
shmdt((void*)shmptr);
}
Second_Process.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
struct memory {
char msg[100];
int status, pid1, pid2, pid3;
};
struct memory* shmptr;
int main()
{
// Second_Process Process Id
int pid = getpid();
// Key Of The Shared Memory
key_t key = ftok("/tmp", 'a');
// Shared Memory Id Fetching
int shmid = shmget(key, sizeof(struct memory), IPC_CREAT | 0666);
// Attaching Second_Process To The Shared Memory
shmptr = (struct memory*)shmat(shmid, NULL, 0);
// Store The Second_Process Process Id In The Shared Memory
shmptr->pid2 = pid;
while (1) {
// Waiting For Third_Process To Get Attached To The Shared Memory
while (shmptr->status != 1)
continue;
sleep(1);
// Writing A Message To The Shared Memory
printf("Enter A Message To Send To Third_Process: \n");
fgets(shmptr->msg, 100, stdin);
// Sending The Message To Third_Process Using The Kill Command
kill(shmptr->pid3, SIGUSR2);
}
// Detaching Second_Process From The Shared Memory
shmdt((void*)shmptr);
}
Third_Process.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
struct memory {
char msg[100];
int status, pid1, pid2, pid3;
};
struct memory* shmptr;
// Handler Function To Read From The Shared Memory
void handler(int signum)
{
// if signum is SIGUSR2, then user 2 is receiving a message from user1
if (signum == SIGUSR2) {
printf("Received From Second: ");
puts(shmptr->msg);
kill(shmptr->pid1, SIGINT);
kill(shmptr->pid2, SIGINT);
kill(shmptr->pid3, SIGINT);
}
}
int main()
{
// Third_Process Process Id
int pid = getpid();
// Key of The Shared Memory
key_t key = ftok("/tmp", 'a');
// Shared Memory Id Fetching
int shmid = shmget(key, sizeof(struct memory), IPC_CREAT | 0666);
// Attaching Third_Process to The Shared Memory
shmptr = (struct memory*)shmat(shmid, NULL, 0);
// Store The Third_Process Process Id In The Shared Memory
shmptr->pid3 = pid;
// Telling Second_Process And First_Process That Third_Process Got Attached To The Shared Memory
shmptr->status = 1;
// Attaching Handler Function To Signal SIGUSR1 And SIGUSR2
signal(SIGUSR1, handler);
signal(SIGUSR2, handler);
while(1){}
// Detaching Third_Process From The Shared Memory
shmdt((void*)shmptr);
}
Is there something wrong with the code?
thanks in advance.
EDIT: it was working well then it started to give the segmentation fault error i don't know why

Related

Using semaphores with shared memory while running multiple processes

I am learning some simple producer/consumer examples involving semaphores, but having a hard time explaining to myself why I am getting a certain result (because I am a noobie to C).
When I run two concurrent processes of the following producer, both processes get hung up and never finish:
#include <stdio.h>
#include <sys/types.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#define BUFF_SIZE 20
typedef struct {
char buffer[BUFF_SIZE];
int nextIn;
int nextOut;
} shared_data;
shared_data *shm, *s;
char sem_name1[] = "mutex";
char sem_name2[] = "empty_slots";
char sem_name3[] = "full_slots";
sem_t *empty_slots;
sem_t *full_slots;
sem_t *mutex;
void Put(char item)
{
sem_wait(empty_slots);
sem_wait(mutex);
s->buffer[s->nextIn] = item;
s->nextIn = (s->nextIn + 1) % BUFF_SIZE;
sem_post(mutex);
printf("Producing %c ... with pid = %d\n", item, getpid());
sem_post(full_slots);
}
void Producer()
{
int i;
for(i = 0; i < 10; i++)
{
sleep(rand()%3);
Put((char)('A'+ i % 26));
}
}
void main()
{
//Create and initialize the semaphores
mutex=sem_open(sem_name1, O_CREAT,0644, 1);
full_slots=sem_open(sem_name3, O_CREAT,0644, 0);
empty_slots=sem_open(sem_name2, O_CREAT,0644, 10);
//Create a key for the segment
key_t key;
key = 1234;
//create the segment
int shmid;
if ((shmid = shmget(key, sizeof(shared_data), IPC_CREAT |0666)) <0)
{
perror("Shmget");
exit(1);
}
//attach to the segment
if ((shm = (shared_data *) shmat(shmid, NULL, 0))==(shared_data *) -1)
{
perror("Shmat");
exit(1);
}
s=shm;
s->nextIn = 0;
Producer();
//detach from the segment
shmdt((void *) shm);
}
The output from the first and second processes, respectively:
Can someone help me understand why this happens (i.e. why do these processes never finish)? Have I created a deadlock? Why or why not? I am completely stumped.
Thanks!

Shared memory linux

I'm trying to work with shared memory at the first time. I created one child process and I write to the shared memory from Parent and change it from Child, before program ends I print shared memory from Parent and shared memory hasn't change, here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <signal.h>
sem_t *semaphore;
int main(){
int i = 0, status;
pid_t pid=fork(), w;
int id;
if ((id = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0666)) == -1){
perror("shmget");
exit(1);
}
int *sh;
if ((sh =(int *) shmat(id, NULL, 0)) == NULL){
perror("shmat");
exit(1);
}
*sh = 10;
if ((semaphore = sem_open("/semaphore", O_CREAT, 0666, 0)) == SEM_FAILED){
perror("semaphore");
exit(1);
}
if (pid==0) {
while(1){
sleep(1);
*sh = 50;
printf("child %d, %d\n", i, *sh);
i++;
if(i == 5){
sem_post(semaphore);
exit(0);
}
}
} else if (pid==-1) {
perror("process error\n");
} else {
printf("Parent, %d\n", *sh);
sem_wait(semaphore);
printf("child end => parent end\n");
printf("Parent, %d\n", *sh);
}
shmctl(id, IPC_RMID, NULL);
sem_close(semaphore);
sem_unlink("/semaphore");
return 0;
}
If I understand shared memory little bit than I can change it from everywhere if I have a pointer in my case is a "sh".
Output of program is:
Parent, 10
child 0, 50
child 1, 50
child 2, 50
child 3, 50
child 4, 50
child end => parent end
Parent, 10
Why is the number in shared memory different in Parent and in Child?
You fork() before you create the shared memory with the key IPC_PRIVATE, so both processes create their own shared memory and don't actually share it.
If you remove the =fork() from
pid_t pid=fork(), w;
and insert
pid = fork();
somewhere after the shmget call, it works the way you expect, since the child process will inherit the shared memory identifier from the parent and not create a different one.

Is it possible in some way to use POSIX semaphores between Docker containers or between a container and the host?

I'm trying to migrate a multiprocess application to Docker. Different processes will be placed in different Docker container.
The application uses shared memory to exchange data and semaphores to synchronize. I already recompiled Docker in order to do not use the IPC namespace and I effectively checked with sudo ipcs -m that the shared memory buffers are accessible from the different containers.
The problem is that semaphores are not working. I wrote these simple programs to check the behavior of POSIX semaphores in Docker:
/* To be compiled with -lpthread */
#include <stdio.h>
#include <fcntl.h>
#include <semaphore.h>
int main(void) {
int ret, val;
sem_t * mySem;
printf("[ONE] Opening the semaphore...\n");
mySem = sem_open("sem1", O_CREAT, 0777, 0);
if (mySem == SEM_FAILED) {
printf("[ONE] Error on sem_open()\n");
return -1;
}
ret = sem_post(mySem);
getchar(); // Awful way to block execution of [ONE] for a while...
printf("[ONE] Waiting for [TWO]...\n");
ret = sem_wait(mySem);
printf("[ONE] Wait ended\n");
ret = sem_unlink("sem1");
printf("[ONE] Semaphore destroyed\n");
return 0;
}
The second program is:
/* To be compiled with -lpthread */
#include <stdio.h>
#include <fcntl.h>
#include <semaphore.h>
int main(void) {
int ret;
int val;
sem_t * mySem;
printf("[TWO] Opening the semaphore...\n");
mySem = sem_open("sem1", O_CREAT, 0777, 0);
if (mySem == SEM_FAILED) {
printf("[TWO] Error on sem_open()\n");
return -1;
}
ret = sem_getvalue(mySem, &val);
printf("[TWO] Semaphore's value is %d\n", val);
printf("[TWO] Waiting for [ONE]...\n");
ret = sem_wait(mySem);
printf("[TWO] Wait ended\n");
printf("[ONE] Doing sem_post() on semaphore...\n");
ret = sem_post(mySem);
ret = sem_close(mySem);
printf("[TWO] Semaphore closed\n");
return 0;
}
In both I omitted lots of controls like if (ret != 0) {...} in order to maintain readability of the question.
I run the first program on the host machine, the second one in a Docker container. The result is that the second program waits forever...
The question is: is it possible in some way to use POSIX semaphores between Docker containers or between a container and the host?
I solved the problem using shared memory between Docker containers as explained in this question.
The following code is a modified version of this tutorial.
File server.c
/* To be compiled with -lpthread */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <semaphore.h>
#define SHM_SIZE 1000
int main(void) {
int shmid;
key_t key;
char *shm;
sem_t * mySem;
/* We'll name our shared memory segment "5678" */
key = 5678;
/* Create the segment.*/
if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666)) < 0) {
perror("shmget");
exit(1);
}
/* Now we attach the segment to our data space */
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
/* Create a new semaphore */
mySem = sem_open("sem1", O_CREAT, 0777, 0);
/* Copy the semaphore on the shared memory segment */
memcpy(shm, mySem, sizeof(*mySem));
/* Do stuff ... */
/* REMEMBER TO USE THE SHARED MEMORY SEGMENT */
/* AND NOT THE LOCAL mySem, USE (sem_t*)shm INSTEAD! */
/* Finally, we wait until the other process
* changes the first character of our memory
* to '*', indicating that it has read what
* we put there.
*/
while (*shm != '*')
sleep(1);
/* Mark the memory segment to be destroyed */
shmctl(shmid, IPC_RMID, NULL);
/* Detach of the memory segment */
shmdt(&shm);
sem_unlink("sem1");
return 0;
}
File client.c
/* To be compiled with -lpthread */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <semaphore.h>
#define SHM_SIZE 1000
int main(void) {
int shmid;
key_t key;
char *shm;
int ret, val;
key = 5678;
if ((shmid = shmget(key, SHM_SIZE, 0666)) < 0) {
perror("shmget");
exit(1);
}
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
/* SEMAPHORE IS IN THE SHARED MEMORY SEGMENT */
/* USE (sem_t*)shm TO ACCESS IT */
*shm = '*';
shmdt(&shm);
sem_close("sem1");
return 0;
}
The code examples miss lots of controls due to readability purposes.
I run the server on the host machine, the client inside a Docker container and checked that the semaphore was accessible from both processes.

Adding Semaphore to a program - C in Linux

I am relatively new to programming, especially in the C Language.
I got an assignment to write a simple program in C and executing it in Linux.
I've written the code already as below:
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
#include<stdlib.h>
#define BUFSZ 4096
int shmid;
int shmkey = 12222;
int main()
{
/* ----- Creating Shared memory ----- */
shmid=shmget(IPC_PRIVATE,BUFSZ,0666);
if(shmid<0)
{
perror("shmget");
exit(EXIT_FAILURE);
}
printf(" Segment Created: %d \n", shmid);
/* ----- Attaching Memory to Shared memory ----- */
char *shmbuf;
if((shmbuf=shmat(shmid,0,0))<0)
{
perror("shmat");
exit(EXIT_FAILURE);
}
printf("Segmet Attached at %p \n", shmbuf);
//system("ipcs -m");
/* ----- Creating Process Using Fork ----- */
int p,i; //i is counter
for (i=1; i<=20; i++) //loop for counter
{
p=fork(); //defining fork
if (p<0)
{
printf("Fork Failed"); //Fork Fails if P<0
exit(-1);
}
else if (p==0) //Child Process
{
printf("Counter: %d\t Process ID: %d\n" ,i,getpid());
//Prints Counter Value and Process ID.
}
else //Parent Process
{
wait(NULL); //Waits Child Process to Complete
exit(0);
}
}
/* ----- Deattaching Memory -----*/
if((shmdt(shmbuf))<0)
{
perror("shmat");
exit(EXIT_FAILURE);
}
printf("Segmet Deattached at %p \n", shmbuf);
//system("ipcs -m");
/* ----- Exiting Program ----- */
exit(0);
puts("\n End\n");
}
I now have to apply the concept of semaphore to this program, using semget(), semop(), and semctl(). Can I please get help on how to use the three functions in my program?
The advantage of semaphores over other synchronization mechanisms is that they can be used to synchronize two related or unrelated processes trying to access the same resource.
Related Process
The processes are said to be related if the new process is created from within an existing process, which ends up in duplicating the resources of the creating process. Such processes are called related processes. The following example shows how the related processes are synchronized.
file prog.c
#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(int argc, char **argv) { int fd, i,count=0,nloop=10,zero=0,*ptr; sem_t mutex;
//open a file and map it into memory
fd = open("log.txt",O_RDWR|O_CREAT,S_IRWXU); write(fd,&zero,sizeof(int)); ptr = mmap(NULL,sizeof(int),PROT_READ |PROT_WRITE,MAP_SHARED,fd,0); close(fd);
/* create, initialize semaphore */ if( sem_init(&mutex,1,1) < 0)
{
perror("semaphore initilization");
exit(0);
} if (fork() == 0) { /* child process*/
for (i = 0; i < nloop; i++) {
sem_wait(&mutex);
printf("child: %d\n", (*ptr)++);
sem_post(&mutex);
}
exit(0); } /* back to parent process */ for (i = 0; i < nloop; i++) {
sem_wait(&mutex);
printf("parent: %d\n", (*ptr)++);
sem_post(&mutex); } exit(0); }
gcc prog.c -lpthread
In this example, the related process access a common piece of memory, which is synchronized.
Unrelated Process
Processes are said to be unrelated if the two processes are unknown to each other and no relationship exists between them. For example, instances of two different programs are unrelated process. If such programs try to access a shared resource, a semaphore could be used to synchronize their access. The following source code demonstrates this:
file 1: server.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define SHMSZ 27
char SEM_NAME[]= "vik";
int main()
{
char ch;
int shmid;
key_t key;
char *shm,*s;
sem_t *mutex;
//name the shared memory segment
key = 1000;
//create & initialize semaphore
mutex = sem_open(SEM_NAME,O_CREAT,0644,1);
if(mutex == SEM_FAILED)
{
perror("unable to create semaphore");
sem_unlink(SEM_NAME);
exit(-1);
}
//create the shared memory segment with this key
shmid = shmget(key,SHMSZ,IPC_CREAT|0666);
if(shmid<0)
{
perror("failure in shmget");
exit(-1);
}
//attach this segment to virtual memory
shm = shmat(shmid,NULL,0);
//start writing into memory
s = shm;
for(ch='A';ch<='Z';ch++)
{
sem_wait(mutex);
*s++ = ch;
sem_post(mutex);
}
//the below loop could be replaced by binary semaphore
while(*shm != '*')
{
sleep(1);
}
sem_close(mutex);
sem_unlink(SEM_NAME);
shmctl(shmid, IPC_RMID, 0);
_exit(0);
}
gcc server.c -lpthread -o server
File 2: client.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define SHMSZ 27
char SEM_NAME[]= "vik";
int main()
{
char ch;
int shmid;
key_t key;
char *shm,*s;
sem_t *mutex;
//name the shared memory segment
key = 1000;
//create & initialize existing semaphore
mutex = sem_open(SEM_NAME,0,0644,0);
if(mutex == SEM_FAILED)
{
perror("reader:unable to execute semaphore");
sem_close(mutex);
exit(-1);
}
//create the shared memory segment with this key
shmid = shmget(key,SHMSZ,0666);
if(shmid<0)
{
perror("reader:failure in shmget");
exit(-1);
}
//attach this segment to virtual memory
shm = shmat(shmid,NULL,0);
//start reading
s = shm;
for(s=shm;*s!=NULL;s++)
{
sem_wait(mutex);
putchar(*s);
sem_post(mutex);
}
//once done signal exiting of reader:This can be replaced by another semaphore
*shm = '*';
sem_close(mutex);
shmctl(shmid, IPC_RMID, 0);
exit(0);
}
gcc client.c -lpthread -o client
The above executables (client and server) demonstrate how semaphore could be used between completely different processes.
In addition to the applications shown above, semaphores can be used cooperatively to access a resource. Please note that a semaphore is not a Mutex. A Mutex allows serial access to a resource, whereas semaphores, in addition to allowing serial access, could also be used to access resources in parallel. For example, consider resource R being accessed by n number of users. When using a Mutex, we would need a Mutex "m" to lock and unlock the resource, thus allowing only one user at a time to use the resource R. In contrast, semaphores can allow n number of users to synchronously access the resource R.

semaphore concurrency

In the following code, wouldn't a mutex be created, in the child, as a copy of its parent's? Hence there're two copies of mutexs now -- one in child, and one in parent. How can it be synchronized? As far as I can remember, you need one copy that are shared by multiple processes in order to make it synchronize.
#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(int argc, char **argv)
{
int fd, i,count=0,nloop=10,zero=0,*ptr;
sem_t mutex;
//open a file and map it into memory
fd = open("log.txt",O_RDWR|O_CREAT,S_IRWXU);
write(fd,&zero,sizeof(int));
ptr = mmap(NULL,sizeof(int), PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
close(fd);
/* create, initialize semaphore */
if( sem_init(&mutex,1,1) < 0)
{
perror("semaphore initilization");
exit(0);
}
if (fork() == 0) { /* child process*/
for (i = 0; i < nloop; i++) {
sem_wait(&mutex);
printf("child: %d\n", (*ptr)++);
sem_post(&mutex);
}
exit(0);
}
/* back to parent process */
for (i = 0; i < nloop; i++) {
sem_wait(&mutex);
printf("parent: %d\n", (*ptr)++);
sem_post(&mutex);
}
exit(0);
}
You must not confuse a mutex with a semaphore. A semaphore might allow several threads/processes to access a resource, a mutex allows only ONE concurrent access to a resource.
As stated here you would need to create a named semaphore to make cross-process-synchronisation possible.
You must create a semaphore in your parent process and access is using sem_open in the child process to achieve synchronisation.

Resources