system V semaphores C - c

I’m trying to use the system V semaphores, but I'm not able to control their value with semop, and so what they do. I should have three total processes that alternate with each other with semaphores that regulate the game turns. If anyone can help me with a practical example I would be very grateful.
PROCESS1
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sem.h>
#define KSEM 2292
#define KKSEM 9922
int main(int argc, char *argv[]){
struct sembuf x;
x.sem_num = 0;
x.sem_op = -1;
x.sem_flg = 0;
int idserver, idclient;
int val1 = 0, val2 = 0;
// declaration
idserver = semget (KSEM, 1, IPC_CREAT | IPC_EXCL | 0666);
idclient = semget (KKSEM, 1, IPC_CREAT | IPC_EXCL | 0666);
if (idserver <0){
perror("idserver: ");
_exit(1);
}
if (idclient <0){
perror("idclient: ");
_exit(1);
}
printf("hello1");
// intializing
semctl(idserver, 0, SETVAL, val1); //server set to 0
semctl(idclient, 0, SETVAL, val2); //client set to 0
printf("ciaoserver1");
int a;
a = semop (idserver, &x, 1);
printf("waiting for client...");
printf("VALUE SERVER: %i \n", a);
return 0;
}
PROCESS2
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sem.h>
#define KSEM 2292
#define KKSEM 9922
int main(int argc, char *argv[]){
struct sembuf x;
x.sem_num = 0;
x.sem_op = 1;
x.sem_flg = 0;
struct sembuf y;
y.sem_num = 0;
y.sem_op = 0;
y.sem_flg = 0;
struct sembuf z;
y.sem_num = 0;
y.sem_op = -2;
y.sem_flg = 0;
int idserver, idclient;
int val1 = 0, val2 = 0;
// declaration
idserver = semget (KSEM, 1, IPC_EXCL | 0666);
if(idserver < 0) {
perror("idserver: ");
_exit(1);
}
idclient = semget (KKSEM, 1, IPC_EXCL | 0666);
if(idclient<0){
perror("idclient: ");
_exit(1);
}
// initialize
semctl(idserver, 0, SETVAL, val1); //server set to 0
semctl(idclient, 0, SETVAL, val2); //client set to 0
printf("CLIENT1");
int a;
a = semop (idclient, &x, 1);
semop (idclient, &y, 1);
semop (idclient, &x, 1);
semop (idclient, &y, 1);
semop (idserver, &y, 1);
printf("VALUE CLIENT 1: %i", a);
return 0;
}

Related

System V - Semaphore operation doesn't allow process to operate

Here's a simple example:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <signal.h>
#include <sys/shm.h>
#include <errno.h>
#include <time.h>
typedef union semun
{
int val;
struct semid_ds *buf;
ushort *array;
}semun;
int main(int argc, char *argv[]) {
int key = ftok("test.c", 1);
semun t;
int sem_id = semget(key, 1 , 0666 | IPC_CREAT | IPC_EXCL);
printf("%d", sem_id);
if(sem_id != -1){
printf("Creating a new semaphore...\n");
t.val = 1;
semctl(sem_id, 0, SETVAL, &t);
}
else if (errno == EEXIST) {
printf("Connecting...");
sem_id = semget(key, 1, 0);
}
else {
printf("LINUX Error");
exit(0);
}
struct sembuf P;
P.sem_num = 0;
P.sem_op = -1;
P.sem_flg = 0;
semop(sem_id, &P, 1);
printf("Hello\n");
semctl(sem_id, 0, IPC_RMID);
return 0;
}
The code bellow semop doesn't get printed out, yet I have an example of to me exactly the same code on the side which works. What could be wrong with this code? I've checked the semaphore array and emptied it before each run.
The problem was with the & sign in this line.
semctl(sem_id, 0, SETVAL, &t);

Synchronizing two child processes with semaphores in c

I have to create a program that synchronizes two processes each printing only a single letter so that whenever we observe the output of the program, the difference between the amount of "A" and "B" is no greater than 2.
So this would be accepted:
BAABBAABBABA
this wouldn't be because it prints 4 B's and only 2 A's:
ABBABB
So for starters i decided to use the POSIX semaphores.
I created two semaphores , giving them all the permissions using the sem_open
Then i created two child processes and for each child process i open the semaphores i created as described in the man page for sem_open and manipulate them.
I don't think it's the logic of the sem_post and sem_wait that's at fault here, since the program seems to ignore them.
So my question is. What goes wrong?
Edit: I don't really need the solution to the problem. Some guidance alone would be much appreciated and welcoming as an answer. Thank you in advance!
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <semaphore.h>
int main(void){
sem_t *semA = sem_open("/semA", O_CREAT|O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO, 0); //Initialize semaphore(= 0) for process A
sem_t *semB = sem_open("/semB", O_CREAT|O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO, 0); //Initialize semaphore(= 0) for process B
if (fork()){ // parent process
if(fork()){}
else{
sem_t *childsemA = sem_open("/semA", 0);
sem_t *childsemB = sem_open("/semB", 0);
while(1){
printf("A");
sem_post(childsemB);
sem_wait(childsemA);
}
}
}
else{
sem_t *childsemA = sem_open("/semA", 0);
sem_t *childsemB = sem_open("/semB", 0);
while(1){
printf("B"); // child2 process
sem_post(childsemA);
sem_wait(childsemB);
}
}
return 0;
}
Output:
May i suggest you to use System V semaphores? This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/sem.h>
#include "Semaphores.h"
#define SEM1_KEY (key_t)888
#define SEM2_KEY (key_t)1234
int sem1, sem2;
int main()
{
pid_t pid;
sem1 = semget(SEM1_KEY, 1, IPC_CREAT | 0666);
if(sem1 < 0)
{
fprintf(stderr, "\nSEMGET Failed\n");
exit(EXIT_FAILURE);
}
sem2 = semget(SEM2_KEY, 1, IPC_CREAT | 0666);
if(sem1 < 0)
{
fprintf(stderr, "\nSEMGET Failed\n");
exit(EXIT_FAILURE);
}
SEM_SET(sem1, 1);
SEM_SET(sem2, 0);
if((pid = fork()) == -1)
{
fprintf(stderr, "\nError in fork()\n");
exit(EXIT_FAILURE);
}
if(pid == 0)
{
while(1)
{
SEM_WAIT(sem2);
printf("%c", 'B');
fflush(stdout);
sleep(1);
SEM_POST(sem1);
}
}
while(1)
{
SEM_WAIT(sem1);
printf("%c", 'A');
fflush(stdout);
sleep(1);
SEM_POST(sem2);
}
wait(0);
SEM_DEL(sem1);
SEM_DEL(sem2);
exit(EXIT_SUCCESS);
}
And this is the header file Semaphores.h which includes the System V semaphores implementation:
#include <sys/sem.h>
union semun
{
int val;
struct semid_ds * buf;
unsigned short * array;
};
int SEM_SET(int sem_id, int sem_val)
{
union semun sem_union;
sem_union.val = sem_val;
return semctl(sem_id, 0, SETVAL, sem_union);
}
int SEM_DEL(int sem_id)
{
return semctl(sem_id, 0, IPC_RMID);
}
int SEM_WAIT(int sem_id)
{
struct sembuf sem_buf;
sem_buf.sem_num = 0;
sem_buf.sem_op = -1;
sem_buf.sem_flg = SEM_UNDO;
return semop(sem_id, &sem_buf, 1);
}
int SEM_POST(int sem_id)
{
struct sembuf sem_buf;
sem_buf.sem_num = 0;
sem_buf.sem_op = 1;
sem_buf.sem_flg = SEM_UNDO;
return semop(sem_id, &sem_buf, 1);
}
The result will be this:
ABABABABABABABABA and so on
fflush() was probably the problem, but your code has some leaks, you need to understand what is a critical section, and you need to check for the return values of fork().

Working with semaphores and shared memory under Linux

I need to write a program that is creating a N amount of sub processes and every single one of them adds one to a shared memory variable. My idea is to use semaphores and shared memory, but the processes are not waiting for each other and the shared memory variable is also not working as I want it.
mydefs.h
#ifndef __MYDEFS__H__
#define __MYDEFS__H__
// Includes
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <memory.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/shm.h>
#endif // __MYDEFS__H__
main.c
#include "mydefs.h"
#define PROC_COUNT 3
#define INITAL_MARKER_VALUE 0
#define PID_LEN 32
char mypid[PID_LEN];
int main()
{
int i, shm_id;
sem_t mutex;
if(sem_init(&mutex,1,1) < 0)
{
perror("semaphore initilization");
exit(0);
}
shm_id = shmget(IPC_PRIVATE, 4*sizeof(int), IPC_CREAT | 0666);
if (shm_id < 0) {
printf("shmget error\n");
}
int *shmpointer = shmat(shm_id,0,0);
memset(mypid, 0, sizeof(mypid));
sprintf(mypid, "%06d", getpid());
for(i = 0; i < PROC_COUNT; i++)
{
if (fork() == 0)
{
while(sem_wait(&mutex)!=0);
execl("slaveproc", "slaveproc", mypid, (char *)0);
shmpointer += 1;
sem_post(&mutex);
perror("\n Can't exec slave program. Cause ");
exit(1);
}
}
sleep(1);
printf("%d\n", *shmpointer);
return 0;
}
slaveproc.c
#include "mydefs.h"
int marker; // Marker value
int main(int argc, char *argv[])
{
master_pid = atoi(argv[1]);
printf("\n --------------------------------------");
printf("\n I'm the slave proc!");
printf("\n My pid: %d", getpid());
printf("\n My master's pid: %d", master_pid);
printf("\n --------------------------------------");
for(;;) pause();
return 0;
}
The problem (or at least "a problem") is that mutex is not in shared memory: it's allocated on the stack. When you fork(), the new process will have a completely separate copy from the old process, so calling sem_wait(&mutex) on one process will not affect the other process's mutex at all.
You should put mutex in the shared memory:
int main()
{
int i, shm_id;
shm_id = shmget(IPC_PRIVATE, sizeof(sem_t) + 4*sizeof(int), IPC_CREAT | 0666);
if (shm_id < 0) {
printf("shmget error\n");
}
int *shmpointer = shmat(shm_id,0,0);
sem_t *mutex = shmpointer;
shmpointer = (void*)shmpointer + sizeof(sem_t);
if(sem_init(mutex,1,1) < 0)
{
perror("semaphore initilization");
exit(0);
}
memset(mypid, 0, sizeof(mypid));
sprintf(mypid, "%06d", getpid());
for(i = 0; i < PROC_COUNT; i++)
{
if (fork() == 0)
{
while(sem_wait(mutex)!=0);
execl("slaveproc", "slaveproc", mypid, (char *)0);
shmpointer += 1;
sem_post(mutex);
perror("\n Can't exec slave program. Cause ");
exit(1);
}
}
sleep(1);
printf("%d\n", *shmpointer);
return 0;
}
You're also never writing to the memory in shmpointer (perhaps you meant (*shmpointer) += 1?), but I'll let you figure that out on your own.

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;
}

procs, fork(), and mutexes

I want to create n processes running in parallel and have them lock a mutex, increment a counter, and then unlock and exit.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t mutex;
int main(int argc, char **argv) {
if (argc != 2)
return 0;
int n = atoi(argv[1]);
int i = 0;
int status = 0;
pthread_mutex_init(&mutex, NULL);
pid_t pid = 1;
static int *x;
x = mmap(NULL, sizeof *x, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
*x = 0;
printf("Creating %d children\n", n);
for(i = 0; i < n; i++) {
if (pid != 0)
pid = fork();
}
if (pid == 0) {
pthread_mutex_lock(&mutex);
*x = *x + 1;
printf("[CHLD] PID: %d PPID: %d X: %d\n", getpid(), getppid(), *x);
pthread_mutex_unlock(&mutex);
exit(0);
}
wait(&status);
printf("[PRNT] PID: %d X: %d\n", getpid(), *x);
munmap(x, sizeof *x);
return 0;
}
./procs 10000 however does not return with x=10000
I think this is because the mutex isn't shared between the processes, but what's the correct way to share the mutex?
Here's a port of my example in the comment using pthread_mutex. First time I've done this, but seems to work:
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <stdbool.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <pthread.h>
typedef struct
{
bool done;
pthread_mutex_t mutex;
} shared_data;
static shared_data* data = NULL;
void initialise_shared()
{
// place our shared data in shared memory
int prot = PROT_READ | PROT_WRITE;
int flags = MAP_SHARED | MAP_ANONYMOUS;
data = mmap(NULL, sizeof(shared_data), prot, flags, -1, 0);
assert(data);
data->done = false;
// initialise mutex so it works properly in shared memory
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&data->mutex, &attr);
}
void run_child()
{
while (true)
{
puts("child waiting. .. ");
usleep(500000);
pthread_mutex_lock(&data->mutex);
if (data->done) {
pthread_mutex_unlock(&data->mutex);
puts("got done!");
break;
}
pthread_mutex_unlock(&data->mutex);
}
puts("child exiting ..");
}
void run_parent(pid_t pid)
{
puts("parent sleeping ..");
sleep(2);
puts("setting done ..");
pthread_mutex_lock(&data->mutex);
data->done = true;
pthread_mutex_unlock(&data->mutex);
waitpid(pid, NULL, NULL);
puts("parent exiting ..");
}
int main(int argc, char** argv)
{
initialise_shared();
pid_t pid = fork();
if (!pid) {
run_child();
}
else {
run_parent(pid);
}
munmap(data, sizeof(data));
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>
typedef struct {
pthread_mutex_t mutex;
int data;
}MUTEX_N_DATA;
int main(int argc, char **argv) {
if (argc != 2)
return 0;
int n = atoi(argv[1]);
int i = 0;
bool wait = true;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pid_t pid = 1;
MUTEX_N_DATA *x;
x = mmap(NULL, sizeof(MUTEX_N_DATA), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
x->data = 0;
pthread_mutex_init(&x->mutex, &attr);
printf("Creating %d children\n", n);
for(i = 0; i < n; i++) {
if (pid != 0) {
pid = fork();
printf("Created Child %d \n",pid);
}
}
if (pid == 0) {
pthread_mutex_lock(&x->mutex);
x->data = x->data + 1;
printf("[CHLD] PID: %d PPID: %d X: %d\n", getpid(), getppid(), x->data);
pthread_mutex_unlock(&x->mutex);
exit(0);
}
while(wait){
pthread_mutex_lock(&x->mutex);
if(x->data == n){
wait = false;
}
pthread_mutex_unlock(&x->mutex);
usleep(100000);
}
printf("[PRNT] PID: %d X: %d\n", getpid(), x->data);
munmap(x, sizeof *x);
return 0;
}
The wait() waits only until one of the child exits. with following changes it works.
mutex attribute set to shared & moved to mmap memory.
parent waiting for the count to reach the number of childrens.
https://man7.org/linux/man-pages/man2/fork.2.html
https://man7.org/linux/man-pages/man2/wait.2.html

Resources