//I think the final code now in this post, should have fixed all the issues I've had. Thank you everyone!
I have written code in C that should lock and unlock shared memory via semaphores and write one Byte into. I would want the written data to alternate between "message" and "read".
Maybe I am misunderstanding semaphores and how their lock functionality works?
I added the while(1) to only to have to loop in one process with the other contiously running, only doing something when the if-condition applies.
I seem to end up in nirvana however, as the program does not complete.
I'd appreciate any help!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <semaphore.h>
void latenz_Ausgabe(time_t tv_secStartLatenz, time_t tv_secEndLatenz, long tv_nsecStartLatenz, long tv_nsecEndLatenz)
{
struct timespec startLatenz = {tv_secStartLatenz, tv_nsecStartLatenz};
struct timespec endLatenz = {tv_secEndLatenz, tv_nsecEndLatenz};
double nanoSekunden = difftime(endLatenz.tv_nsec, startLatenz.tv_nsec);
double sekunden = difftime(endLatenz.tv_sec, startLatenz.tv_sec);
double differenzZeit = (sekunden nanoSekunden / ((double) 1e9)) / 1000.0; //Zeit berechnen in Sekunden, sowie auf eine Messung runterrechnen
double latenz = (differenzZeit * ((double) 1e3)) / 2; //1e3 für Millisekunden, / 2 Da hin und zurück gemessen
printf("Durchschnittliche Latenz: %.6lf milliseconds\n", latenz);
}
int main() {
struct timespec startLatenz, endLatenz;
int sem_id;
int sem_idtwo;
int shm_id;
int value;
key_t key = ftok("shared_memory", 1); // Create key shared memory
key_t keytwo = ftok("semaphore", 1); // Create key semaphore
key_t keythree = ftok("semaphoretwo", 1); // Create key semaphore
if((shm_id = shmget(key, 16777216, IPC_CREAT | 0666)) == -1){ // -1 indicates error //create shared memory
perror("semctl");
exit(1);
} else {
printf("Shared memory created with id: %d \n", shm_id);
}
if((sem_id = semget(keytwo, 1, IPC_CREAT | 0666)) == -1){ // -1 indicates error // create semaphore
perror("semctl");
exit(1);
} else {
printf("Semaphore created with id: %d \n", shm_id);
}
if((sem_idtwo = semget(keythree, 1, IPC_CREAT | 0666)) == -1){ // -1 indicates error // create semaphore
perror("semctl");
exit(1);
} else {
printf("Semaphore created with id: %d \n", shm_id);
}
struct sembuf sem_lock = {0, -1, 0}; // Struct for semop to lock
struct sembuf sem_unlock = {0, 1, 0}; // Struct for semop to unlock
char *data = (char *)shmat(shm_id, NULL, 0); // Connect Shared-Memorys to Process
pid_t pid;
if((semctl(sem_id, 0, SETVAL, 1)) == -1){ // -1 indicates error //initialize the semaphore with value 1
perror("semctl");
exit(1);
} else {
printf("Semaphore initialized \n");
}
if((semctl(sem_idtwo, 0, SETVAL, 1)) == -1){ // -1 indicates error //initialize the semaphore with value 1
perror("semctl");
exit(1);
} else {
printf("Semaphore initialized \n");
}
pid = fork();
if(pid < 0){
printf("Error");
return 1;
}
//malloc allocates exactly one Byte
char *message = (char *) malloc(1);
char *read = (char *) malloc(1);
message[0] = 'a';
read[0] = 'b';
clock_gettime(CLOCK_MONOTONIC, &startLatenz);
if (pid == 0) {
// Process 2:
while(1){
semop(sem_idtwo, &sem_lock, 1);
if (data[0] == message[0]){
memcpy(data, read, 1);
}
semop(sem_idtwo, &sem_unlock, 1);
}
}
else {
// Process 1:
for(int i = 0; i < 1000; i ){
//1
if (i > 0){ //because data[0] is never equal to read[0] during first loop
semop(sem_id, &sem_lock, 1);
//char dummy = data[0]; // Could save current value before overwrite
if (data[0] == read[0]){
memcpy(data, message, 1);
}
semop(sem_id, &sem_unlock, 1);
//printf("Values: %c %c \n", dummy, data[0]); //Could print
}
else{ //because data[0] is never equal to read[0] during first loop
semop(sem_id, &sem_lock, 1);
//char dummy = data[0]; // Could save current value before overwrite
memcpy(data, message, 1);
semop(sem_id, &sem_unlock, 1);
}
}
}
clock_gettime(CLOCK_MONOTONIC, &endLatenz);
latenz_Ausgabe(startLatenz.tv_sec, endLatenz.tv_sec, startLatenz.tv_nsec, endLatenz.tv_nsec);
shmdt(data); // Remove shared-memory from process
shmctl(shm_id, IPC_RMID, NULL); // Delete shared memory
semctl(sem_id, 0, IPC_RMID); // Delete semaphore
return 0;
}
I tried doing it with two locks, I tried with three operations, I tried different loops (inside/outside of the child/parent process)
CodePudding user response:
As far as I understand, you want to see an output that sometimes prints a
and sometimes prints b
. The printing is done here:
semop(sem_id, &sem_lock, 1);
memcpy(data, message, 1);
semop(sem_id, &sem_unlock, 1);
printf("%c \n", data[0]); <----------
So you have just copied a
into data and then you do the printing. So it's not extremely surprising that your print out will mostly show a
I changed the code a little to use while(1)
for both loops. When running the program and looking at the terminal, it seemed that a
was printed all the time.
Then I send the output to grep and grep'ed for b
, i.e "./a.out | grep b" and now I do see b
being printed.
My conclusion: Since you do the print just after setting data
to a
, you will print an a
in most cases. Further, if you only look at the terminal, you most likely won't be able to notice the few prints of b
.
Instead try:
semop(sem_id, &sem_lock, 1);
char dummy = data[0]; // Save current value before overwrite
memcpy(data, message, 1);
semop(sem_id, &sem_unlock, 1);
printf("%c %c \n", dummy, data[0]);
then maybe you'll see a different result.
But... you don't have any code ensuring an alternating access. Alternating access don't come by itself. You need code to ensure alternating write access. For instance you could add code so that writes to data
is only done when data
contains the value written by the other process.
Something like:
if (data[0] == message[0]) memcpy(data, read, 1);
and
if (data[0] == read[0]) memcpy(data, message, 1);