This program creates a pid and shares two integers (base and height) through the shared memory.
The parent process time asks four times to insert two integers and wait for the pid to calculate the area.
After the four cycles, the ppid waits for the end of its child, deletes the shared memory and the semaphore and ends. The child waits for the new variable (base, height with semaphore), calculates the area, and prints it, and after the four iterations, it ends.
I have to use semaphore for process synchronization and to regulate the critical section. The problem consists of the pid, it works only one time.
I'm expected to receive the area after i put the integer, the first time work but the following time doesent.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <string.h>
#define SEM_KEY (key_t)8765
#define SHM_KEY (key_t)9876
/** Questa union la trovate digitando "man semctl" */
union semun
{
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
/** Tipo di dato condiviso */
struct sh_data
{
int altezza;
int base;
};
/** Funzioni di appoggio per operare con i semafori */
int sem_set(int semid, int val);
int sem_down(int semid);
int sem_up(int semid);
void controlla_area(int, struct sh_data *);
int main()
{
pid_t pid;
int semid, shmid, i;
struct sh_data *data;
// SEMAFORO
// Creazione del semaforo
semid = semget(SEM_KEY, 1, 0666 | IPC_CREAT);
// Inizializzazione semaforo
sem_set(semid, 1);
// SHARED MEMORY
// Creazione shared memory
shmid = shmget(SHM_KEY, sizeof(struct sh_data), 0666 | IPC_CREAT);
// Attach della shm allo spazio di indirizzi del processo
data = (struct sh_data *)shmat(shmid, NULL, 0);
// Processo figlio
pid = fork();
switch (pid)
{
case -1:
perror("Errore fork");
exit(EXIT_FAILURE);
case 0:
controlla_area(semid, data);
exit(EXIT_SUCCESS);
default:
break;
}
// Processo padre
for (i = 0; i < 4; i++)
{
sem_down(semid);
printf("Inserisci la base: ");
scanf("%d", &(data->base));
printf("Inserisci l'altezza: ");
scanf("%d", &(data->altezza));
sem_up(semid);
wait(NULL);
}
// Detach della shared memory
shmdt(data);
// Eliminazione della shared memory
shmctl(shmid, IPC_RMID, NULL);
// Eliminazione semaforo
semctl(semid, 0, IPC_RMID);
exit(EXIT_SUCCESS);
}
void controlla_area(int semid, struct sh_data *data)
{
int area;
sem_down(semid);
area = data->base * data->altezza;
printf("L'area del triangolo è %d\n", area);
sem_up(semid);
}
int sem_set(int semid, int val)
{
union semun s;
s.val = val;
/* Inizializza il valore del semaforo */
return semctl(semid, 0, SETVAL, s);
}
int sem_down(int semid)
{
struct sembuf buff;
buff.sem_num = 0;
buff.sem_op = -1;
buff.sem_flg = SEM_UNDO;
/* Decrementa il valore del semaforo */
return semop(semid, &buff, 1);
}
int sem_up(int semid)
{
struct sembuf buff;
buff.sem_num = 0;
buff.sem_op = 1;
buff.sem_flg = SEM_UNDO;
/* Incrementa il valore del semaforo */
return semop(semid, &buff, 1);
}
The problem consists of the pid, it works only one time.
This is because the child process calls controlla_area just once, and executes its contents
void controlla_area(int semid, struct sh_data *data)
{
int area;
sem_down(semid);
area = data->base * data->altezza;
printf("L'area del triangolo è %d\n", area);
sem_up(semid);
}
just once, and then exits.
Note that both the parent process and the child process will vie for control of the shared memory via the semaphore. There is no guarantee as to which process will first decrement the semaphore, but it is likely the parent process will, due to the overhead of starting a new process (see also: context switch).
The fact that the child process does surely gain access to the semaphore is made possible by the wait(NULL); that blocks the execution of the parent process, during the first iteration of the loop that writes to shared memory, until the child process terminates.
Placing a blocking action in the parent process, after the switch statement (e.g., sleep(5)) will make the race condition obvious. The child process will likely get some CPU time, and will gain access to the shared memory via the semaphore decrement. It will then invoke Undefined Behaviour by reading the indeterminate values in the shared memory.
Incrementing a semaphore is not a blocking action. There is no guarantee that the process that just incremented the semaphore will not be the same process to next decrement the semaphore. This is a matter of scheduling, and is implementation defined.
A single semaphore should not be relied upon to create this kind of synchronization between processes.
With minimal changes, an additional semaphore can create a lockstep between the parent process and the child process, such that each process waits for the other to complete its work.
A loop is added to the child process.
The semaphores are initialized such that the parent process operates first. The additional sem_down(semid_to); ensures the parent process waits for the child process to finish printing, before terminating it via a signal.
#define _POSIX_C_SOURCE 200809L
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <string.h>
#define SEM_KEY (key_t)8765
#define SHM_KEY (key_t)9876
/** Questa union la trovate digitando "man semctl" */
union semun
{
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
/** Tipo di dato condiviso */
struct sh_data
{
int altezza;
int base;
};
/** Funzioni di appoggio per operare con i semafori */
int sem_set(int semid, int val);
int sem_down(int semid);
int sem_up(int semid);
void controlla_area(int, int, struct sh_data *);
int main()
{
pid_t pid;
int semid_to, semid_from, shmid, i;
struct sh_data *data;
// SEMAFORO
// Creazione del semaforo
semid_to = semget(SEM_KEY, 1, 0666 | IPC_CREAT);
semid_from = semget(1 + SEM_KEY, 1, 0666 | IPC_CREAT);
// Inizializzazione semaforo
sem_set(semid_to, 1);
sem_set(semid_from, 0);
// SHARED MEMORY
// Creazione shared memory
shmid = shmget(SHM_KEY, sizeof(struct sh_data), 0666 | IPC_CREAT);
// Attach della shm allo spazio di indirizzi del processo
data = (struct sh_data *)shmat(shmid, NULL, 0);
// Processo figlio
pid = fork();
switch (pid)
{
case -1:
perror("Errore fork");
exit(EXIT_FAILURE);
case 0:
controlla_area(semid_to, semid_from, data);
exit(EXIT_SUCCESS);
default:
break;
}
// Processo padre
for (i = 0; i < 4; i++)
{
sem_down(semid_to);
printf("Inserisci la base: ");
scanf("%d", &(data->base));
printf("Inserisci l'altezza: ");
scanf("%d", &(data->altezza));
sem_up(semid_from);
}
sem_down(semid_to);
kill(pid, SIGTERM);
wait(NULL);
// Detach della shared memory
shmdt(data);
// Eliminazione della shared memory
shmctl(shmid, IPC_RMID, NULL);
// Eliminazione semaforo
semctl(semid_to, 0, IPC_RMID);
semctl(semid_from, 0, IPC_RMID);
exit(EXIT_SUCCESS);
}
void controlla_area(int semid_to, int semid_from, struct sh_data *data)
{
int area;
while (1) {
sem_down(semid_from);
area = data->base * data->altezza;
printf("L'area del triangolo è %d\n", area);
sem_up(semid_to);
}
}
int sem_set(int semid, int val)
{
union semun s;
s.val = val;
/* Inizializza il valore del semaforo */
return semctl(semid, 0, SETVAL, s);
}
int sem_down(int semid)
{
struct sembuf buff;
buff.sem_num = 0;
buff.sem_op = -1;
buff.sem_flg = SEM_UNDO;
/* Decrementa il valore del semaforo */
return semop(semid, &buff, 1);
}
int sem_up(int semid)
{
struct sembuf buff;
buff.sem_num = 0;
buff.sem_op = 1;
buff.sem_flg = SEM_UNDO;
/* Incrementa il valore del semaforo */
return semop(semid, &buff, 1);
}
Note that there are many things that could go wrong here, due to the fact that almost no error handling is done whatsoever. semget, semctl, semop, shmget, shmat, shmctl, shmdt, scanf, kill and wait can all fail.
In a non-trivial program none of these return values should be ignored with regards to errors.
Related
I trying to study the inter process comunication. I trying to write a program that send a message between father and child. First the father read a input file and send the rows to child, the child re-send the rows to the father. The processs communicate with the semaphores (FULL,EMPTY,MUTEX) using WAIT and SIGNAL functions. I use 6 semaphores. Why the last father_final doesn't receive nothing ?
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ipc.h>
#define DIM 1024
#define MUTEX 0 // sem mutex
#define FULL 1 // sem full
#define EMPTY 2 // sem empty
#define MUTEX2 3 // sem mutex
#define FULL2 4 // sem full
#define EMPTY2 5 // sem empty
#define TYPE_P 2
#define TYPE_F 3
#define TYPE_FN 4
typedef struct
{
char text[DIM];
int eof;
long type;
int nChild;
} msg;
int WAIT(int sem_id, int sem_num)
{
struct sembuf ops[1] = {{sem_num, -1, 0}};
return semop(sem_id, ops, 1);
}
int SIGNAL(int sem_id, int sem_num)
{
struct sembuf ops[1] = {{sem_num, +1, 0}};
return semop(sem_id, ops, 1);
}
void father(int shm_id, int sem_id, char *filename, msg *p)
{
FILE *r_stream;
char tmp[DIM];
if ((r_stream = fopen(filename, "r")) == NULL)
{
perror("fopen");
exit(1);
}
while (fgets(tmp, DIM, r_stream) != NULL)
{
printf("Father -> %s", tmp);
WAIT(sem_id, EMPTY);
WAIT(sem_id, MUTEX);
strcpy(p->text, tmp);
p->eof = 0;
p->type = TYPE_F;
p->nChild = 1;
SIGNAL(sem_id, MUTEX);
SIGNAL(sem_id, FULL);
}
WAIT(sem_id, EMPTY);
WAIT(sem_id, MUTEX);
strcpy(p->text, "-1\n");
p->eof = 1;
p->type = TYPE_F;
p->nChild = 1;
SIGNAL(sem_id, MUTEX);
SIGNAL(sem_id, FULL);
fclose(r_stream);
shmdt(p);
exit(0);
}
void filter(int shm_id, int sem_id, int child, msg *p)
{
char text[DIM];
int eof;
long type;
int nChild;
while (1)
{
WAIT(sem_id, FULL);
WAIT(sem_id, MUTEX);
WAIT(sem_id, EMPTY2);
WAIT(sem_id, MUTEX2);
strcpy(text, p->text);
eof = p->eof;
type = p->type;
nChild = p->nChild;
printf("Filter-> %s", text);
printf("Send to father: %s", text);
SIGNAL(sem_id, MUTEX2);
SIGNAL(sem_id, FULL2);
SIGNAL(sem_id, MUTEX);
SIGNAL(sem_id, EMPTY);
}
exit(0);
}
void father_final(int shm_id2, int sem_id, msg *p2)
{
while (1)
{
WAIT(sem_id, FULL2);
WAIT(sem_id, MUTEX2);
if(strcmp(p2->text,"-1\n")==0)break;
printf("Messaggio ricevuto: %s\n", p2->text);
SIGNAL(sem_id, MUTEX2);
SIGNAL(sem_id, EMPTY2);
}
exit(0);
}
int main(int argc, char *argv[])
{
/* code */
int shm_id, sem_id, shm_id2;
msg *p, *p2;
if (argc == 1 || argc == 2)
{
fprintf(stderr, "uso: %s file.txt filter-1...filte-n \n", argv[0]);
exit(1);
}
// creo area di memoria condivisa
if ((shm_id = shmget(IPC_PRIVATE, sizeof(msg), IPC_CREAT | 0600)) == -1)
{
perror("shmget");
exit(1);
}
// attacco area di memoria
if ((p = (msg *)shmat(shm_id, NULL, 0)) == (msg *)-1)
{
perror("shmat");
exit(1);
}
// creo i semafori
if ((sem_id = semget(IPC_PRIVATE, 3, IPC_CREAT | 0600)) == -1)
{
perror("semget");
exit(1);
}
// inizializzo semafori
semctl(sem_id, MUTEX, SETVAL, 1);
semctl(sem_id, EMPTY, SETVAL, 1);
semctl(sem_id, FULL, SETVAL, 0);
semctl(sem_id, MUTEX2, SETVAL, 1);
semctl(sem_id, EMPTY2, SETVAL, 1);
semctl(sem_id, FULL2, SETVAL, 0);
int child = argc - 2;
char *filename = argv[1];
if (fork() == 0)
{
filter(shm_id, sem_id, child, p);
}
else
{
father(shm_id, sem_id, filename, p);
}
father_final(shm_id,sem_id,p);
// distruggo area di memoria condivisa
shmctl(shm_id, IPC_RMID, NULL);
// rimuovo i semafoti
semctl(sem_id, FULL, IPC_RMID, 0);
semctl(sem_id, EMPTY, IPC_RMID, 0);
semctl(sem_id, MUTEX, IPC_RMID, 0);
semctl(sem_id, FULL2, IPC_RMID, 0);
semctl(sem_id, EMPTY2, IPC_RMID, 0);
semctl(sem_id, MUTEX2, IPC_RMID, 0);
return 0;
}
This is my output:
Father -> Fratelli d'Italia,
Father -> l'Italia s'è desta,
Filter-> Fratelli d'Italia,
Send to father: Fratelli d'Italia,
Father -> dell'elmo di Scipio
Filter-> l'Italia s'è desta,
Send to father: l'Italia s'è desta,
Father -> s'è cinta la testa.
Filter-> dell'elmo di Scipio
Send to father: dell'elmo di Scipio
Father -> Dov'è la vittoria?
Filter-> s'è cinta la testa.
Send to father: s'è cinta la testa.
Father -> Le porga la chioma,
Filter-> Dov'è la vittoria?
Send to father: Dov'è la vittoria?
Father -> ché schiava di RomaIddio la creò.
Filter-> Le porga la chioma,
Send to father: Le porga la chioma,
Filter-> ché schiava di RomaIddio la creò.
Send to father: ché schiava di RomaIddio la creò.
Filter-> -1
Send to father: -1
I don't receive messages like "Msg received -> ......"
I have a program that is supposed to do this:
The main program creates a chunk of shared memory (to share with his future children) the size of a struct called ClientInfo which contains 2 integers and a string. Then the program asks the user for a number which is stored in the variable n
The main program creates n children.Then the children wait for a SIGUSR1 signal from their father.
The main program sends a SIGUSR1 signal to all his children.
Each child reads a string from the terminal, writes it in the shared memory and also increments in one unit both shared integers. Then he sends a SIGUSR1 to his father, sleeps between 1 and 10 seconds and then ends.
Each time the father recieves a SIGUSR1 it prints the contenent of the shared memory, then only ends when all of his children end.
The "catch" is that this is college homework and they told us that the father must be able to print the content of the shared memory one time for each children, so n times in total. Also we can't use sigwait() or global variables (unless global variables are the only way).
Also each time I run the program it just hangs indefinitely asfter asking for n
I know there must be some sort of race condition but I'm really bad at that and I can't figure out what's wrong.
Thank you in advance.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <sys/wait.h>
#define SHM_NAME "/shm_example"
#define SEM1 "/example_sem1"
#define SEM2 "/example_sem2"
#define NAME_MAX 100
typedef struct{
int previous_id; //!< Id of the previous client.
int id; //!< Id of the current client.
char name[NAME_MAX]; //!< Name of the client.
} ClientInfo;
int main(void) {
int i,n,*pids;
int fd_shm;
int error;
struct sigaction act;
ClientInfo *example_struct;
sigset_t mask, oldmask;
sem_t *sem_write = NULL,*sem_read = NULL;
sigemptyset(&mask);
sigemptyset(&oldmask);
sigaddset(&mask, SIGUSR1);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
printf("Introduzca un numero:\n");
scanf("%d",&n);
if(!(pids = malloc(n*sizeof(int))))
exit(EXIT_FAILURE);
if ((sem_write = sem_open(SEM1, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1)) == SEM_FAILED) {
perror("sem_open");
exit(EXIT_FAILURE);
}
if ((sem_read = sem_open(SEM2, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1)) == SEM_FAILED) {
perror("sem_open");
exit(EXIT_FAILURE);
}
sigemptyset(&(act.sa_mask));
act.sa_flags = 0;
act.sa_handler = SIG_IGN;
if (sigaction(SIGUSR1, &act, NULL) < 0) {
perror("sigaction");
exit(EXIT_FAILURE);
}
fd_shm = shm_open(SHM_NAME,O_RDWR | O_CREAT | O_EXCL,S_IRUSR | S_IWUSR);
if(fd_shm == -1) {
fprintf (stderr, "Error creating the shared memory segment \n");
return EXIT_FAILURE;
}
error = ftruncate(fd_shm, sizeof(ClientInfo));
if(error == -1) {
fprintf (stderr, "Error resizing the shared memory segment \n");
shm_unlink(SHM_NAME);
return EXIT_FAILURE;
}
/* Map the memory segment */
example_struct = (ClientInfo *)mmap(NULL, sizeof(*example_struct), PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm, 0);
if(example_struct == MAP_FAILED) {
fprintf (stderr, "Error mapping the shared memory segment \n");
shm_unlink(SHM_NAME);
return EXIT_FAILURE;
}
(example_struct->previous_id)=-1;
(example_struct->id)=0;
for(i=0;i<n;i++){
pids[i] = fork();
if (pids[i] < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pids[i] == 0) {
char nombre[NAME_MAX];
srand(getpid() ^ (i * 1091));
sigsuspend(&oldmask);
sem_wait(sem_write);
(example_struct->previous_id)++;
printf("Introduzca un nombre:\n");
scanf("%s",nombre);
memcpy(example_struct->name, nombre, sizeof(nombre));
(example_struct->id)++;
kill(getppid(),SIGUSR1);
sem_post(sem_write);
sleep(1 + (rand()%10));
exit(EXIT_SUCCESS);
}
}
sigprocmask(SIG_UNBLOCK, &mask, &oldmask);
kill(0,SIGUSR1);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
while(1){
sigsuspend(&oldmask);
/*if(wait(NULL)<0){
sem_close(sem_write);
sem_close(sem_read);
sem_unlink(SEM1);
sem_unlink(SEM2);
munmap(example_struct, sizeof(*example_struct));
shm_unlink(SHM_NAME);
exit(EXIT_SUCCESS);
}*/
sem_wait(sem_read);
sem_wait(sem_write);
sem_post(sem_read);
printf("El cliente es %s con id %d y el previo es %d\n",example_struct->name,example_struct->id,example_struct->previous_id);
fflush(stdout);
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
sem_wait(sem_read);
sem_post(sem_write);
sem_post(sem_read);}
}
You can try something like that:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdatomic.h>
#define SHM_NAME "/shm_example"
#define NAME_MAX 100
typedef struct{
char name[NAME_MAX]; //!< Name of the client.
} ClientInfo;
atomic_bool done = ATOMIC_VAR_INIT(false);
void child_handler(int dummy) {
(void)dummy;
done = true;
}
int main(void) {
int i,n,*pids;
int fd_shm;
int error;
struct sigaction act;
ClientInfo *example_struct;
printf("Introduzca un numero:\n");
scanf("%d",&n);
if(!(pids = malloc(n*sizeof(int))))
exit(EXIT_FAILURE);
sigemptyset(&(act.sa_mask));
act.sa_flags = 0;
act.sa_handler = child_handler;
if (sigaction(SIGUSR1, &act, NULL) < 0) {
perror("sigaction");
exit(EXIT_FAILURE);
}
fd_shm = shm_open(SHM_NAME,O_RDWR | O_CREAT | O_EXCL,S_IRUSR | S_IWUSR);
if(fd_shm == -1) {
fprintf (stderr, "Error creating the shared memory segment \n");
return EXIT_FAILURE;
}
error = ftruncate(fd_shm, sizeof(ClientInfo));
if(error == -1) {
fprintf (stderr, "Error resizing the shared memory segment \n");
shm_unlink(SHM_NAME);
return EXIT_FAILURE;
}
/* Map the memory segment */
example_struct = (ClientInfo *)mmap(NULL, sizeof(*example_struct), PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm, 0);
if(example_struct == MAP_FAILED) {
fprintf (stderr, "Error mapping the shared memory segment \n");
shm_unlink(SHM_NAME);
return EXIT_FAILURE;
}
for (i = 0; i < n ; i++) {
pids[i] = fork();
if (pids[i] < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pids[i] == 0) {
/* Child */
while (!done) {
/* Wait for signal */
sleep(1);
}
printf("child %d wakes up\n", getpid());
sprintf(example_struct->name, "my pid is %d", getpid());
kill(getppid(),SIGUSR1);
sleep(1 + (rand()%10));
exit(EXIT_SUCCESS);
}
}
/* only father here */
for (i = 0; i < n; i++) {
done = false;
kill(pids[i], SIGUSR1);
printf("Waiting child %d\n", pids[i]);
while (!done) {
/* Wait for signal */
sleep(1);
}
printf("Answer from %d: %s\n", pids[i], example_struct->name);
wait(NULL);
}
}
In the end, I don't really understand why you used semaphores if you are asked to use signal only, thus I removed them. I also removed the id do get a less chatty code, you may add them back if you need it.
The point here is I perform the wait with a while() loop waiting for a boolean atomic variable.
So the father trig a signal on the first child, then waits for it to signal back, then do the same with the next one, and so on...
so you get such a sequence:
$ ./example
Introduzca un numero:
5
Waiting child 14314
child 14314 wakes up
Answer from 14314: my pid is 14314
Waiting child 14315
child 14315 wakes up
Answer from 14315: my pid is 14315
Waiting child 14316
child 14316 wakes up
Answer from 14316: my pid is 14316
Waiting child 14317
child 14317 wakes up
Answer from 14317: my pid is 14317
Waiting child 14318
child 14318 wakes up
Answer from 14318: my pid is 14318
I'm trying to implement producer-consumer problem in C using processes and System V IPC and I'm stuck on one thing. This is early version of my code (without implementing queue operations or even producer and consumer executing in loop) that I was using to learn and test how semaphores work:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <time.h>
#include "sem.h"
#include "shm.h"
#define BUFFER_SIZE 9
int full;
int empty;
int mutex;
struct buff {
int queue[BUFFER_SIZE];
} *buffer;
void producer();
void consumer();
int main() {
int parent_pid, pid, i;
parent_pid = getpid();
int shmid = allocate_shared_memory(sizeof(*buffer));
buffer = (struct buff *) attach_shared_memory(shmid);
for (i = 0; i < BUFFER_SIZE; i++) {
buffer->queue[i] = 0;
}
full = sem_allocate();
empty = sem_allocate();
mutex = sem_allocate();
printf("Full %d\n", full);
printf("Empty %d\n", empty);
printf("Mutex %d\n", mutex);
sem_init(full, 0);
sem_init(empty, BUFFER_SIZE);
sem_init(mutex, 1);
printf("Full value %d\n", sem_get_val(full));
printf("Empty value %d\n", sem_get_val(empty));
printf("Mutex value %d\n", sem_get_val(mutex));
srand(time(0));
pid = fork();
if (!pid) {
printf("Producer here: %d\n", getpid());
producer();
printf("Full value after prod() %d\n", sem_get_val(full));
return 0;
} else printf("Created new producent: %d\n", pid);
sleep(1);
pid = fork();
if (!pid) {
printf("Consumer here: %d\n", getpid());
printf("Full value before cons() %d\n", sem_get_val(full)); //here I always get 0
consumer();
return 0;
} else printf("Created new consumer: %d\n", pid);
while (1)
{
int status;
pid_t done = wait(&status);
if (done == -1)
{
if (errno == ECHILD) break; // no more child processes
}
else
{
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
exit(1);
}
}
}
if (getpid() == parent_pid) {
sem_deallocate(full);
sem_deallocate(empty);
sem_deallocate(mutex);
}
}
void producer() {
sem_wait(empty);
sem_wait(mutex);
printf("Producer is producing!\n");
buffer->queue[0]=0;
sem_post(mutex);
sem_post(full);
}
void consumer() {
sem_wait(full);
sem_wait(mutex);
printf("Consumer is consuming!\n");
sem_post(mutex);
sem_post(empty);
}
int sem_allocate() {
return semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
}
void sem_deallocate(int semid) {
if (semctl(semid, 0, IPC_RMID, NULL) == -1)
{
perror("Error releasing semaphore!\n");
exit(EXIT_FAILURE);
}
}
int sem_init(int semid, int value) {
union semun arg;
arg.val = value;
if (semctl(semid, 0, SETVAL, arg) == -1) {
perror("semctl");
return -1;
}else return 1;
}
int sem_wait(int semid) {
printf("Someone is waiting %d\n", semid);
struct sembuf sem = { 0, -1, SEM_UNDO };
return semop(semid, &sem, 1);
}
int sem_post(int semid) {
printf("Someone is posting %d\n", semid);
struct sembuf sem = { 0, 1, SEM_UNDO };
return semop(semid, &sem, 1);
}
int sem_get_val(int semid) {
return semctl(semid, 0, GETVAL, 0);
}
int allocate_shared_memory(int size) {
return shmget(IPC_PRIVATE, size, IPC_CREAT | SHM_W | SHM_R);
}
void deallocate_shared_memory(const void* addr, int shmid) {
shmctl(shmid, IPC_RMID, 0);
}
void* attach_shared_memory(int shmid) {
return shmat(shmid, NULL, 0);
}
sem.h:
#include <sys/types.h>
#include <errno.h>
union semun {
int val;
struct semid_ds *buf;
ushort* array;
};
int sem_post(int);
int sem_wait(int);
int sem_allocate();
void sem_deallocate(int);
int sem_init(int, int);
int sem_get_val(int);
shm.h:
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
int allocate_shared_memory(int size);
void deallocate_shared_memory(const void* addr, int shmid);
void* attach_shared_memory(int shmid);
Why before executing consumer function value of full semaphore is 0? Even if right after producer finishes his job the value is 1...
I'm new to this kind of topics so maybe there is an obvious explenation of the situation, but I have no idea what can I do and hope you can help me.
You initialize the "full" semaphore to zero. Your "child" producer, prior to exiting calls your sem_post() function, which calls semop() with a SEM_UNDO argument.
int sem_post(int semid) {
printf("Someone is posting %d\n", semid);
struct sembuf sem = { 0, 1, SEM_UNDO };
return semop(semid, &sem, 1);
}
The Ubuntu Linux man page for semop says the following about SEM_UNDO:
... If an operation specifies SEM_UNDO, it will be automatically
undone when the process terminates.
This means, "producer" increments "full" prior to exiting, then after it exits the system "undoes" the increment (i.e. it decrements "full") setting it back to zero.
So,for the purposes of the "full" semaphore, you should NOT specify SEM_UNDO.
I have a problem, I would like to do a fork for example a fork of 20processes, this fork created, should not do anything until the last one is not created, and I want to do it with semaphore, how can I implement it?
for (i=0; i<20; i++) {
switch (fork()) {
case: -1:
exit(EXIT_FAILURE);
case 0:
execve(....);
exit(EXIT_FAILURE);
default:
printf ("Child Created!");
}
}
Here's you homework. You can pay me later.
#include <semaphore.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
sem_t *sem;
if(MAP_FAILED==(sem=mmap(0, sizeof(*sem), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0)))
{ perror("mmap"); exit(EXIT_FAILURE); }
if(0>sem_init(sem, 1/*shared*/, 0/*init val*/))
{ perror("sem_init"); exit(EXIT_FAILURE); }
for(int i=0; i<20; i++){
switch(fork()){
case -1: perror("fork"); /*you'll need to kill the children here*/
exit(EXIT_FAILURE);
case 0:
puts("waiting");
sem_wait(sem);
puts("running");
exit(0);
default:
puts("Child created");
}
}
puts("done forking. signalling children");
usleep(1000000);
for(int i=0; i<20; i++)
sem_post(sem);
}
The idea is simple. Init the (necessarily, shared) semaphore to zero and make each child wait on it before it does its thing.
When you're done forking in the parent, you post to the semaphore 20 times so that each child's sem_wait call completes.
Same thing with with SysV semaphores:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
//the manpage says we should define this union (as follows)
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
int main()
{
key_t key;
char tmpl[]="/tmp/XXXXXX";
{
int tmpfd;
if(0>(tmpfd = mkstemp(tmpl)))
{ perror("mkstemp"); exit(EXIT_FAILURE); }
close(tmpfd);
}
//Get a key
puts(tmpl);
key=ftok(tmpl, 'A');
int sem;
int ec = EXIT_SUCCESS;
if(0>(sem = semget(key, 1 /*1 sem*/, IPC_CREAT|IPC_EXCL|0600)))
{ perror("semget"); goto fail; }
if(0>semctl(sem, 0 /*ix*/, SETVAL, (union semun){ .val=0 }))
{ perror("sem init"); goto fail; }
for(int i=0; i<20; i++){
switch(fork()){
case -1: { perror("fork"); /*you'll need to kill the children here*/ exit(EXIT_FAILURE); }
case 0:
puts("waiting");
semop(sem, (struct sembuf[1]){{ .sem_op=-1 }}, 1);
puts("running");
exit(0);
default:
puts("Child created");
}
}
puts("done forking. signalling children");
usleep(1000000);
//can up it by 20 in one go
semop(sem, (struct sembuf[1]){{ .sem_op=+20 }}, 1);
goto success;
fail: ec = EXIT_FAILURE;
success:
semctl(sem, 0, IPC_RMID);
unlink(tmpl);
exit(ec);
}
Here you have to dance around the SysV IPC API ugliness and the need to set up an file-based key, but then, as a reward, you get to increment the semaphore by 20 in one go.
The program should create 200000 integers and write 2000 to a shared memory. A forked process should read 2000 from shared memory and the parent should write the next 2000 to shared memory.
if i use the code below without sleep, the parent first creates all 200000 integers and then the child reads the same integers from shared memory.
With sleep everything looks good, but we have to use semaphore.
shm.c (parent):
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <sys/wait.h>
#define N_DATA 200000
#define N_SHARED 2000
#define LOCK -1
#define UNLOCK 1
static struct sembuf semaphore;
char shmidArg[32];
char semidArg[32];
int *shmData;
int i, j;
int status;
char *strsignal(int sig);
pid_t pid;
static int shmid;
static int semid;
char *strsignal(int sig);
/** Semaphore Operation */
static int semaphore_operation (int op) {
semaphore.sem_num = 1;
semaphore.sem_op = op;
semaphore.sem_flg = IPC_NOWAIT;
if( semop (semid, &semaphore, 1) == -1) {
perror(" semop ");
exit (EXIT_FAILURE);
}
return 1;
}
int main(int argc, char **argv) {
/* Ein Shared-Memory-Segment einrichten */
shmid = shmget(IPC_PRIVATE, N_SHARED*sizeof(int), IPC_CREAT | SHM_R | SHM_W);
if (shmid == -1) {
perror("shmid");
exit(1);
}
printf("Shared-Memory-ID: %d\n",shmid);
/* Pointer zu Shared-Memory-Segment erhalten */
shmData = (int *)shmat(shmid,0, 0);
if (shmData == (int *)(-1)) {
perror("shmat");
exit(1);
}
/* Semaphore anlegen */
semid = semget(IPC_PRIVATE, 1, IPC_CREAT | SHM_R | SHM_W);
if (semid < 0) {
perror("semid");
exit(1);
}
printf ("Semaphor-ID : %d\n", semid);
/* Semaphor mit 1 initialisieren */
if (semctl (semid, 0, SETVAL, (int) 1) == -1) {
perror("semctl");
}
snprintf(shmidArg,32, "%d", shmid);
snprintf(semidArg,32, "%d", semid);
/** erstellen des Kindprozesses */
pid = fork();
// Kindprozess
if (pid == 0) {
execlp("./shm_child",shmidArg,semidArg,NULL);
} else if (pid < 0) {
perror("Kindprozess konnte nicht erzeugt werden!");
return 1;
}
// Elternprozess
else {
/** ininitalisieren des Zufallsgenerator durch aktuellen Zeitstempel */
srand48(time(NULL));
for(i=0;i<N_DATA;i=i+N_SHARED) {
semaphore_operation(LOCK);
for (j=0; j<N_SHARED; j++) {
shmData[j] = lrand48();
//MSZ
//printf("SHM-->%d-->%d\n",i+1,shmData[i]);
}
// if(i == 0 || i == 2000) {
printf("Parent-->%d-->0-->%d\n",i,shmData[0]);
printf("Parent-->%d-->1999->%d\n",i,shmData[1999]);
// }
semaphore_operation(UNLOCK);
//sleep(1);
}
}
//MSZ
//sleep(2);
printf("PID: %d\n", pid);
if (waitpid(pid, &status, 0) == -1) {
perror("wait konnte nicht erzeugt werden!");
return 1;
}
if (WIFEXITED(status)) {
printf("Exitcode: %d\n", WEXITSTATUS(status));
semctl (semid, 0, IPC_RMID, 0);
shmctl (shmid, IPC_RMID, NULL);
//If process terminaded by a signal
} else if (WIFSIGNALED(status)) {
printf("Signal: %d %s\n", WTERMSIG(status), strsignal(WTERMSIG(status)));
semctl (semid, 0, IPC_RMID, 0);
shmctl (shmid, IPC_RMID, NULL);
}
}
shm_child.c (Child):
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#define N_DATA 6000
#define N_SHARED 2000
#define LOCK -1
#define UNLOCK 1
int i,j;
int *shmData;
static int shmid;
static int semid;
static struct sembuf semaphore;
/** Semaphore Operation */
static int semaphore_operation (int op) {
semaphore.sem_num = 0;
semaphore.sem_op = op;
semaphore.sem_flg = SEM_UNDO;
if( semop (semid, &semaphore, 1) == -1) {
perror(" semop ");
exit (EXIT_FAILURE);
}
return 1;
}
int main(int argc, char **argv) {
shmid = atoi(argv[0]);
semid = atoi(argv[1]);
printf("\nshm_child shared memoryid:%d\n",shmid);
printf("shm_child Semaphoren-ID:%d\n",semid);
/* Pointer auf Shared-Memory erstellen */
shmData = (int *)shmat(shmid,0,0);
if (shmData == (int *)(-1)) {
perror("shmat");
exit(1);
}
for(i=0;i<N_DATA;i=i+N_SHARED) {
semaphore_operation(LOCK);
for(j=0;j<N_SHARED;j++) {
//printf("%d-->%d --> %d\n",i,j+1,shmData[j]);
}
// if(i == 0 || i == 2000) {
printf("child-->%d-->0-->%d\n",i,shmData[0]);
printf("child-->%d-->1999->%d\n",i,shmData[1999]);
// }
semaphore_operation(UNLOCK);
sleep(1);
}
return 0;
}
Please help us
Thank you guys
Edit: Thank you very much for your answers. I can't mark the right answer because i dont know what its right. But i dont want try anything more. 15 hours are enough
The writer process shall give reader a permission to read, and wait for the reading completion. After that the reader shall give writer a permission to proceed, and wait for writing completion.
This goal cannot be achieved with a single semaphore. You need two, along the lines of:
// parent aka writer
writer_barrier = semaphore(UNLOCKED);
reader_barrier = semaphore(LOCKED);
start_reader();
while(...) {
lock(writer_barrier);
write_data();
unlock(reader_barrier);
}
// child aka reader
while(....)
lock(reader_barrier);
read_data();
unlock(writer_barrier);
}