Adding Semaphore to a program - C in Linux - c

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.

Related

sem_unlink(): permission denied on macOS

I am working on a school assignment using semaphores, every time I restart my mechine everything works as expected but after running my code, the second try gives undefined results. I've come to a conclusion that my machine don't give me permission to unlink any created semaphores, and checking the errno showed that my conclusion was correct. It gives errno EACCES, how can I fix this problem? I am working on the last visions of Xcode (12.2).
The code I am running:
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h> /* For O_* constants */
#include <errno.h>
const char *semName1 = "my_sema1";
const char *semName2 = "my_sema2";
int main(int argc, char **argv)
{
pid_t pid;
sem_t *sem_id1 = sem_open(semName1, O_CREAT, O_RDWR, 1);
sem_t *sem_id2 = sem_open(semName2, O_CREAT, O_RDWR, 0);
int i, status;
pid = fork();
if (pid) {
for (i = 0; i < 100; i++) {
sem_wait(sem_id1);
putchar('A'); fflush(stdout);
sem_post(sem_id2);
}
sem_close(sem_id1);
sem_close(sem_id2);
wait(&status);
int error = sem_unlink(semName1);
int hej2 = sem_unlink(semName2);
printf("%d \n",error);
if (errno == EACCES){
printf("%d \n",error);
}
} else {
for (i = 0; i < 100; i++) {
sem_wait(sem_id2);
putchar('B'); fflush(stdout);
sem_post(sem_id1);
}
sem_close(sem_id1);
sem_close(sem_id2);
}
}
Appreciate your help
Quick Answer: Run the program as root
Long Answer:
Given this code snippet:
#include <errno.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
sem_t *sem_id1 = sem_open("sem_id1", O_CREAT, O_RDWR, 0);
if (sem_id1 == SEM_FAILED)
{
perror("sem_open");
exit(1);
}
printf("sem_open: Successful\n");
int rc = sem_unlink("sem_id1");
if (rc != 0)
{
perror("sem_unlink");
exit(1);
}
printf("sem_unlink: Successful\n");
return 0;
}
The first time it's run, it will let you create the semaphore, but fail to unlink it:
./main
sem_open: Successful
sem_unlink: Permission denied
The second time it will fail even to create the semaphore:
./main
sem_open: Permission denied
The issue is clearly with permissions, and running the program as root fixes it:
sudo ./main
sem_open: Successful
sem_unlink: Successful
Why does it need root privileges?
Quoting from the man page:
POSIX semaphores come in two forms: named semaphores and unnamed semaphores.
...
Persistence
POSIX named semaphores have kernel persistence: if not removed by sem_unlink(3), a semaphore will exist until the system is shut down.
These are named semaphores.
The fn sem_open and sem_unlink are possibly affecting processes that don't belong to you: imagine if you could run a program that overwrites or removes another process' semaphore without root permissions!

How To Implement IPC Using Shared Memory

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

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.

Wait for a Forked Process when using a Semaphore

I'm trying to code an exercise in C Linux where I have one semaphore with 2 spots and "n" processes entered by argument. I need that the first 2 processes use the semaphore using the 2 spots for 5 secs each and then leave the semaphore for the other remaining processes to do their stuff. The problem is that not all the other processes wait for the semaphore to be free and some of them show a semaphore error (look at the results at the bottom). I believe the problem is on the waits for the child processes, because I have a waitipid and a wait function, but I need that if there's a free spot in the semaphore, any child process running could use it. Here's the code:
//gcc SemaphoreExample.c -o s
//./s 5
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>
void semaphoreTask(int semid, int semnum, int semBusy)
{
struct sembuf data;
data.sem_num = semnum;
data.sem_flg = 0;
data.sem_op = semBusy;
if(semop(semid,&data,1) == -1)
{
printf("\nSemaphore Error\n");
exit(-1);
}
}
int main(int argc, char *argv[])
{
int i, fdSemaphore, quantity, fdsemctl, j;
pid_t pid[15];
system("clear");
if(argc-1 < 1)
{
printf("Some arguments are missing\n");
return EXIT_FAILURE;
}
printf("Number of arguments entered:\n\nargc: %d\n\nValues from the arguments:\n\n",argc-1);
for(i=0;i<argc;i++)
{
printf("argv[%d]: %s\n",i,argv[i]);
}
printf("\n\n");
fdSemaphore = semget(1234,1,IPC_CREAT|0777);
if(fdSemaphore == -1)
{
printf("\nError creating the Semaphore\n");
return EXIT_FAILURE;
}
fdsemctl = semctl(fdSemaphore,0,SETVAL,2);
if(fdsemctl == -1)
{
printf("\nError opening the Semaphore\n");
return EXIT_FAILURE;
}
quantity = atoi(argv[1]);
for(i=0;i<quantity;i++)
{
pid[i] = fork();
if(pid[i] == -1)
{
printf("\nError creating the Child Process\n");
return EXIT_FAILURE;
}
if(pid[i] == 0)
{
semaphoreTask(fdSemaphore,0,-1);
printf("\n[%d] I go to sleep\n",getpid());
sleep(5);
printf("\n[%d] I wake up\n",getpid());
semaphoreTask(fdSemaphore,0,1);
}
else
{
//printf("\nJust wait\n");
waitpid(pid[i],NULL,WNOHANG);
}
}
for(j=0;j<quantity;j++)
{
wait(NULL);
}
semctl(fdSemaphore,0,IPC_RMID);
return EXIT_SUCCESS;
}
This is the result I got:
Result:
Number of arguments entered:
argc: 1
Values from the arguments:
argv[0]: ./s
argv[1]: 5
[2845] I go to sleep
[2844] I go to sleep
[2845] I wake up
[2844] I wake up
Semaphore Error
[2843] I go to sleep
Semaphore Error
Semaphore Error
[2843] I wake up
Semaphore Error
Should I use wait or waitpid only?
The problem is semaphores are getting removed by forked children.
After line
semaphoreTask(fdSemaphore,0,1);
add
exit(0);
It is much simpler to implement what you want if you use sem_post and sem_wait calls. I am on a OpenBSD system and I am assuming that Linux has the same thing.

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