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 -> ......"
Related
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.
I'm reading Modern Operating Systems and there's a exercise that asks you to build a counting-semaphore with a binary-semaphore.
I was wondering if I could do it with semaphores & shared memory (C and POSIX IPC).
I'll leave a simplification of my program here.
typedef struct sem {
int semid; /* contains two semaphores with value set to 1, one for the critical region and the other for locking */
int shmid; /* shared counter */
}Sem;
/* the parent process spawns a few child processes and then waits for them */
void child() {
Sem *s;
s = get_sem();
down_sem(s);
printf("working...");
sleep(5);
printf("finished!");
up_sem(s);
}
void down_sem(Sem *s) {
int n;
enter_critical(s); // down to critical region sem
n = get_counter(s);
if (n == 0) {
exit_critical(s); // up to critical region sem
acquire_lock(s); // down to lock sem
} else {
n--;
exit_critical(s); // up to critical region sem
}
}
void up_sem(Sem *s) {
int n;
enter_critical(s);
n = get_counter(s);
n++;
if (n == 1) {
exit_critical(s);
release_lock(s); // up to lock sem
} else {
exit_critical(s);
}
}
But this doesn't work since some processes block in the lock semaphore forever. I'm just now learning these concepts so my design is probably totally off.
I can share the complete code if you wish.
Thanks in advance!
EDIT: requested mre
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/shm.h>
#define NPROC 5
#define SLOTS 2
#define PATH "."
#define SID 'S'
#define SEMN 2
#define SHMID 'M'
#define SHM_SIZE 32
#define CRIT 0
#define LOCK 1
#define UP 1
#define DOWN -1
typedef struct sem {
int shmid;
int semid;
}Sem;
typedef union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
}Args;
void err (char *msg) {
char error[50];
int n;
n = snprintf(error, 50, "[%d] %s", getpid(), msg);
error[n] = 0;
perror(error);
exit(1);
}
int* get_n(Sem *s) {
int *data = NULL;
data = shmat(s->shmid, (void *)0, 0);
if (data == (int *)(-1))
err("get_n shmat");
return data;
}
void dettach_n(int *data) {
if (shmdt(data) == -1)
err("dettach_n shmdt");
}
void enter_crit(Sem *s) {
struct sembuf sb;
sb.sem_num = CRIT;
sb.sem_op = DOWN;
printf("[%d] enter crit\n", getpid());
if (semop(s->semid, &sb, 1) == -1)
err("enter crit");
}
void exit_crit(Sem *s) {
struct sembuf sb;
sb.sem_num = CRIT;
sb.sem_op = UP;
printf("[%d] exit crit\n", getpid());
if (semop(s->semid, &sb, 1) == -1)
err("exit crit");
}
void acquire_lock(Sem *s) {
struct sembuf sb;
sb.sem_num = LOCK;
sb.sem_op = DOWN;
printf("[%d] acquire lock\n", getpid());
if (semop(s->semid, &sb, 1) == -1)
err("acquire lock");
}
void release_lock(Sem *s) {
struct sembuf sb;
sb.sem_num = LOCK;
sb.sem_op = UP;
printf("[%d] release lock\n", getpid());
if (semop(s->semid, &sb, 1) == -1)
err("release lock");
}
int sem_init(Sem *s, int n) {
key_t key;
Args arg;
int *data;
/* sem */
if ((key = ftok(PATH, SID)) == -1) {
return -1;
}
if ((s->semid = semget(key, SEMN, 0600 | IPC_CREAT)) == -1) {
return -1;
}
arg.val = 1;
if (semctl(s->semid, 0, SETVAL, arg) == -1) {
return -1;
}
if (semctl(s->semid, 1, SETVAL, arg) == -1) {
return -1;
}
/* mem */
if ((key = ftok(PATH, SHMID)) == -1) {
return -1;
}
if ((s->shmid = shmget(key, SHM_SIZE, 0664 | IPC_CREAT)) == -1) {
return -1;
}
data = shmat(s->shmid, (void *)0, 0);
if (data == (int *)(-1)) {
return -1;
}
*data = n;
if (shmdt(data) == -1) {
return -1;
}
return 0;
}
int sem_get(Sem *s) {
key_t key;
if ((key = ftok(PATH, SID)) == -1) {
return -1;
}
if ((s->semid = semget(key, SEMN, 0)) == -1) {
return -1;
}
if ((key = ftok(PATH, SHMID)) == -1) {
return -1;
}
if ((s->shmid = shmget(key, SHM_SIZE, 0)) == -1) {
return -1;
}
return 0;
}
int sem_up(Sem *s) {
int *data;
enter_crit(s);
data = get_n(s);
printf("[%d] read %d\n", getpid(), *data);
(*data)++;
if (*data == 1) {
printf("[%d] now is %d\n", getpid(), *data);
dettach_n(data);
exit_crit(s);
release_lock(s);
} else {
exit_crit(s);
}
return 0;
}
int sem_down(Sem *s) {
int *data;
enter_crit(s);
data = get_n(s);
printf("[%d] checked %d\n", getpid(), *data);
if (*data == 0) {
dettach_n(data);
exit_crit(s);
acquire_lock(s);
} else {
(*data)--;
dettach_n(data);
exit_crit(s);
}
return 0;
}
int sem_rm(Sem *s) {
if (semctl(s->semid, 0, IPC_RMID) == -1)
return -1;
if (shmctl(s->shmid, 0, IPC_RMID) == -1)
return -1;
return 0;
}
void child() {
pid_t pid;
Sem s;
pid = getpid();
printf("\x1b[31m[%d] hello!\033[0m\n", pid);
if (sem_get(&s) == -1) {
perror("sem_get");
exit(1);
}
sem_down(&s);
printf("\x1b[32m[%d] working...\033[0m\n", pid);
sleep(5);
printf("\x1b[32m[%d] finishing...\033[0m\n", pid);
sem_up(&s);
printf("\x1b[34m[%d] **child leaving**\033[0m\n", pid);
exit(0);
}
int main() {
Sem s;
int i;
if (sem_init(&s, SLOTS) == -1) {
perror("sem_init");
exit(1);
}
printf("[%d] parent\n", getpid());
for (i = 0; i < NPROC; i++) {
switch(fork()) {
case 0:
child();
case -1:
perror("fork");
exit(1);
}
}
printf("waiting for children...\n");
for (i = 0; i < NPROC; i++)
wait(NULL);
if (sem_rm(&s) == -1) {
perror("sem_rm");
exit(1);
}
printf("good bye!\n");
return 0;
}
The problem was in the up_sem function. It only does an up to the lock sem (release_lock func) if n was previously 0. This is incorrect since it might be several process waiting.
My solution was adding an extra shared memory counting the waiting processes and doing an up to the lock sem when that number is greater than 0.
I made this program with pipes to communicate two processes with PIPES. Now what I have to do is the same but with FIFO.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <wait.h>
#include <string.h>
int main()
{
int e, p[20], hijo1, hijo2, nbytes, readbytes;
char texto[200], readbuffer[100];
printf("Write the message to send to the other process\n");
fgets(texto, 100, stdin);
pipe(p);
if ((hijo1 = fork()) == -1)
{
printf("ERROR FORK\n");
exit(EXIT_FAILURE);
}
if (hijo1 == 0)
{
printf("Im %d and Im child 1\n", getpid());
close(p[0]);
write(p[1], texto, strlen(texto + 1));
close(p[1]);
exit(0);
}
if ((hijo2 = fork()) == -1)
{
printf("ERROR FORK\n");
exit(EXIT_FAILURE);
}
if (hijo2 == 0)
{
printf("Im %d And Im child 2 \n", getpid());
close(p[1]);
write(1, "message received: ", 24);
while ((nbytes = read(p[0], readbuffer, 8)) == 8)
{
write(1, readbuffer, nbytes);
}
write(1, readbuffer, nbytes);
printf("\n");
close(p[0]);
exit(0);
}
printf("Im %d and Im the father\n", getpid());
waitpid(hijo1, &e, 0);
waitpid(hijo2, &e, 0);
exit(EXIT_SUCCESS);
}
This is what I tried to do but with FIFO
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <wait.h>
#include <string.h>
int main()
{
char texto[200], buf[200];
int fd, fd2, hijo1, hijo2, nbytes;
printf("Ingrese el mensaje para enviar al FIFO\n");
fgets(texto, 100, stdin);
printf("soy %d y soy el padre \n", getpid());
mkfifo("/tmp/mi_fifo", 0666);
if ((hijo1 = fork()) == -1)
{
printf("ERROR FORK\n");
exit(EXIT_FAILURE);
}
if (hijo1 == 0)
{
printf("soy %d y soy el hijo 1 \n", getpid());
fd = open("/tmp/mi_fifo", O_WRONLY);
write(fd, texto, sizeof(texto + 1));
close(fd);
exit(0);
}
if ((hijo2 = fork()) == -1)
{
printf("ERROR FORK\n");
exit(EXIT_FAILURE);
}
if (hijo2 == 0)
{
printf("soy %d y soy el hijo 2 \n", getpid());
fd2 = open("/tmp/mi_fifo", O_RDONLY);
write(1, "el mensaje recibido es: \n", 24);
while (nbytes = read(fd2, buf, 8) == 8)
{
write(1, buf, nbytes);
}
write(1, buf, nbytes);
close(fd2);
exit(0);
}
return 0;
}
This Fifo program is not receiving the Message from the other child process. When I print the buf variable with Write() It shows only one letter. It should show the whole message that's why it is in a while loop. How can I do that? I haven't found any information about fork processes and FIfOs I hope you can help me.
At least two problems:
sizeof(texto + 1) needs to be strlen(texto)+1 to ensure the right size for the string in the buffer.
while (nbytes = read(fd2, buf, 8) == 8) needs to be while ((nbytes = read(fd2, buf, 8)) == 8). Because == has higher precedence than =. What you have assigns either 1 or 0 (boolean result) to nbytes.
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.
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);
}