Locking semaphores in C problem sys/sem - c

EDIT: This peace of code is pretty fine (so take it as example of semaphores ;). Bug in my program was in another place - found by my friend.
I have problem with my functions. Sometimes two processes enter into critical section. I can't find problem in this after I spent 10 hours by debugging. On what I should aim? Is there any possibility to have bud in this piece of code?
// lock semaphore
static int P(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1; /* P() */
sem_b.sem_flg = 0;
if (semop(sem_id, &sem_b, 1) == -1) {
// error
return(0);
}
return(1);
}
// unlock semaphore
static int V(int sem_id)
{
struct sembuf sem_b[1];
sem_b.sem_num = 0;
sem_b.sem_op = 1; /* V() */
sem_b.sem_flg = 0;
if (semop(sem_id, &sem_b, 1) == -1) {
// error
return(0);
}
return(1);
}
static int set_semval(int sem_id) {
// set to 1 (opened semaphore)
if (semctl(sem_id, 0, SETVAL, 1) == -1) {
// error
return(0);
}
return(1);
}
static int get_val(int sem_id)
{
union semun sem_union;
//sem_union.val = 0; ?
return semctl(sem_id, 0, GETVAL, sem_union);
}
The action loop:
// semaphores init
int mutex;
if ((mutex=semget(key+2, 1, 0666))>=0) {
// semaphore exists
fprintf(stderr,"semaphore exists for key %d\n", key+2);
}
if ((mutex=semget(key+2, 1, 0666 | IPC_CREAT)) == -1) {
exit(EXIT_FAILURE);
}
if (!set_semval(mutex)) {
exit(EXIT_FAILURE);
}
fork() // some times with good conditionals
// in some children
while(1) {
P(mutex);
assert(get_val(mutex)==0); // always ok
action(); // sometimes made by two processes at same time - fault
V(mutex);
}
Pls, feel free to edit my question.
Many thanks

in your 'action loop' what do you do if your semaphore does not exist?
currently your 3rd parameter to semget is 0666 or the PERMISSION_RW constant. You may want to use:
shmget(key, 1, PERMISSION_RW | IPC_CREAT);
this way if your semaphore does not exist it will create one.

So bug was at another place...

Related

Semaphore in C - How can I make it alternate?

//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)
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);

Using sys/sem.h in C, How to get the semaphore value?

I am using sys/sem.h in C to implement semaphore, but now I am stuck with a strange problem so I want to check the semaphore value. I write such a function:
int sem_set(int semid, int sem_val)
{
union semun sem_union;
sem_union.val = sem_val;
if (semctl(semid, 0 , SETVAL , sem_union) == -1) return 0;
return 1;
}
int sem_get(int semid)
{
union semun sem_union;
return semctl(semid, 0 , GETVAL , sem_union);
}
int sem_wait(int semid)
{
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = -1;
sb.sem_flg = SEM_UNDO;
if (semop(semid, &sb, 1) == -1)
{
printf("error/n");
return 0;
}
return 1;
}
But the function is going wrong when I have such two processes running:
initially sem.val is set to 0;
process1:
...
printf("%d", sem_get(sem_id));
sem_wait(semid);
...
process2:
...
printf("%d", sem_get(sem_id));
sem_wait(semid);
...
Assuming process 1 run first and executed sem_wait(semid), I guess process 2 should output -1 but actually 0 is printed. How could this happen? is my function wrong? Or the semaphore implementation in sem.h is different to what I learned in the class?
there is already the function sem_getvalue()
here is an example
int sem_getvalue(sem_t *sem, int *valp);
strongly suggest performing a bit of googling for 'how to use semaphores in C'
one such web page is:
http://www.csc.villanova.edu/~mdamian/threads/posixsem.html#getvalue
here is an excerpt from the man page for sem_getvalue
sem_getvalue() places the current value of the semaphore pointed to sem
into the integer pointed to by sval.

C Unix Xcode bug again

I am doing a university project, we have to use the Unix system call.
Right now, I'm really struggling to understand if, in my project, there really is a mistake. This is because, while in terminal it compiles and it starts and finishes without error, on xcode I get several errors.
In particular, I get errors when using semaphores.
I'll try to explain what errors, I receive, but since I'm not native English speakers forgive me in advance if I make some mistakes.
First, the program creates a number of child processes with a fork (). It does depending on how many clientei.txt located (i = iterator).
Immediately I block parent with a semaphore, I run the child up to a certain point, then I block it with a semaphore and I restart the parent.
At this point, the parent should read a message sent by his son, call a function to print the content inside a log.txt and restart the son.
Then the child does other things (including erase the message) and it block.
The parent restart, and everything is repeated for subsequent children.
While in terminal synchronization is perfect (everything happens at the right time without error) this both Linux and Mac, about XCode I had several errors:
semop: Resource temporarily unavailable (if I created more than 5 txt)
semop: File too large (if I created more than 2)
with 2 instead gave me two errors:
semop 1: Interrupted system call (this stops after running both processes)
semop 3: Identifier removed (with this in restarting the second process)
is not so much time that I do C then I do not know what to do. I would like first of all to know if I have to worry (so there is an error), or I have to be quiet because it is a bug in xcode.
If there was a mistake I kindly ask you not to ask me to change the code a lot.
This is mainly because they are close to expiring and I can not afford to do it all again.
I also ask you, if you can, to be as clear as possible. I understand enough English, but not as a mother-tongue, I can not always follow the responses here on StackOverflow.
The code is here:
https://www.dropbox.com/s/2utsb6r5d7kzzqj/xcode%2Bterminal.zip?dl=0
this zip contain a small part of the project that has this problem.
the terminal version works. there is a makefile in this version to simplify the compilation.
xcode version does not work. It contains the Debug folder. Indeed xcode, txt files, it does not read from the root folder where the codes are contained in the folder where it creates the compiled. There is a readme in each case with the procedure in detail.
I tried to minimize, I commented all in English.
I removed the code that was not needed, but I added the file with all the include and functions that use.
here the code:
main.c
key_t key, key_2;
int semid, semid_2;
union semun arg;
union semun arg_2;
struct sembuf sb_2 = {0, -1, 0};
char* nome_file;
nome_file = (char*) malloc(sizeof(char*));
int numero_clienti;
//semaphore for all the child
struct sembuf sb[numero_clienti];
int i_c;
for (i_c = 0; i_c < numero_clienti; i_c++) {
sb[i_c].sem_num = i_c;
sb[i_c].sem_op = -1;
sb[i_c].sem_flg = 0;
}
//cretion of first SEMAPHORE
{
//key creation
if ((key = ftok("cliente0.txt", 'J')) == -1)
{
perror("ftok");
exit(EXIT_FAILURE);
}
//creation of the semaphore
if ((semid = semget(key, numero_clienti, 0666 | IPC_CREAT | IPC_EXCL)) == -1)
{
perror("semget");
exit(EXIT_FAILURE);
}
//set value of all child semaphore
for (i_c = 0; i_c < numero_clienti; i_c++) {
arg.val = 0;
if (semctl(semid, i_c, SETVAL, arg) == -1)
{
perror("semctl");
exit(EXIT_FAILURE);
}
}
}
//cretion of second SEMAPHORE
{
//key creation
if ((key_2 = ftok("cliente1.txt", 'J')) == -1)
{
perror("ftok");
exit(EXIT_FAILURE);
}
//creation of the semaphore
if ((semid_2 = semget(key_2, 1, 0666 | IPC_CREAT | IPC_EXCL)) == -1)
{
perror("semget");
exit(EXIT_FAILURE);
}
//set value of parent semaphore
arg_2.val = 0;
if (semctl(semid_2, 0, SETVAL, arg_2) == -1)
{
perror("semctl");
exit(EXIT_FAILURE);
}
}
while(fd > 0 && pid > 0){
j++;
close(fd);
pid = fork();
if(pid != 0)
{
i++;
sprintf(nome_file, "./cliente%d.txt", i);
fd = open(nome_file, O_RDONLY);
}
switch(pid)
{
//error case
case -1:
{
perror("Error during fork.");
exit(EXIT_FAILURE);
break;
}
//child case
case 0:
{
puts("Child: I'm a child");
messaggio(numero_clienti, j);
puts("Child: I have to do something");
//Start parent
sb_2.sem_op = 1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop");
exit(1);
}
//, stop itself
sb[j].sem_op = -1;
if (semop(semid, &sb[j], 1) == -1)
{
perror("semop");
exit(1);
}
printf("Child: I have to do something else %d\n", getpid());
_exit(EXIT_SUCCESS);
break;
}
//parent case
default:
{
puts("Parent: I'm a parent");
//Stop itself
sb_2.sem_op = -1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop padre");
exit(1);
}
puts("Parent: now I can send the message, my child is blocked");
//restart child
sb[j].sem_op = 1;
if (semop(semid, &sb[j], 1) == -1)
{
perror("semop");
exit(1);
}
//stop itself
sb_2.sem_op = -1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop");
exit(1);
}
puts("Parent: end of while");
break;
}
}
}
puts("Parent: I can restart all my child");
for (i_c = 0; i_c < numero_clienti; i_c++) {
sb[i_c].sem_op = 1;
if (semop(semid, &sb[i_c], 1) == -1)
{
perror("semop");
exit(1);
}
}
puts("I wait the end of my child...");
while (wait(NULL) != -1);
puts("All child end");
//remove semaphore I create
if (semctl(semid, 0, IPC_RMID, arg) == -1)
{
perror("semctl");
exit(1);
}
if (semctl(semid_2, 0, IPC_RMID, arg_2) == -1)
{
perror("semctl");
exit(1);
}
puts("FINE");
return 0;
}
cliente.c
#include "cliente.h"
/**
inside this function child do some thing.
1. at this point it give control to parent after it create a message
2. at this point it remove the message
*/
void messaggio(int numero_clienti, int num_j){
key_t key, key_2;
int semid, semid_2;
struct sembuf sb[numero_clienti];
int i_c;
for (i_c = 0; i_c < numero_clienti; i_c++) {
sb[i_c].sem_num = i_c;
sb[i_c].sem_op = -1;
sb[i_c].sem_flg = 0;
}
struct sembuf sb_2 = {0, -1, 0};
if ((key = ftok("cliente0.txt", 'J')) == -1) {
perror("ftok");
exit(1);
}
if ((semid = semget(key, 1, 0)) == -1) {
perror("semget");
exit(1);
}
if ((key_2 = ftok("cliente1.txt", 'J')) == -1) {
perror("ftok");
exit(1);
}
if ((semid_2 = semget(key_2, 1, 0)) == -1) {
perror("semget");
exit(1);
}
//creation of a message
//1. Restart parent
sb_2.sem_op = 1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop");
exit(1);
}
puts("cambio sem");
//stop itself
sb[num_j].sem_op = -1;
if (semop(semid, &sb[num_j], 1) == -1)
{
perror("semop");
exit(1);
}
//here it can move again
puts("remove message");
puts("Figlio: sono tornato attivo, mio padre aspetta");
}
1st you do
nome_file = (char*) malloc(sizeof(char*));
which allocates 4 or 8 bytes (depending on the platform you compile on: 32 or 64bit).
Then you do
sprintf(nome_file, "./cliente%d.txt", i);
The latter writes to invalid memory, as "./cliente%d.txt" is 14+1 characters long plus the potenial number of digits from i if i>9 or and addtional sign if i<0.
To fix this allocate what is needed:
nome_file = malloc(13 + 10 + 1 + 1); /* 13 for the filename,
10 for the digits,
1 for a potential sign,
1 the C-"strings" 0-terminator. */
This is a really ugly bug, which is expected to be the main issue in your code.
Also in the sources (you linked) in function read_line() you allocate memory, which you do not properly initialise, but later depend on its content.
main.c:20
char* myb2 = (char*) malloc(sizeof(char*));
malloc() does not initialise the memory it allocates, so either do:
char * myb2 = calloc(1, sizeof(char*));
of add and addtional call to
memset(mb2, 0, sizeof(char*));
after the call to malloc().
This bug is nasty either.
Also^2 you should build using gcc's options -std=c99 -D_XOPEN_SOURCE.
That is because:
You are using C constructs available from C99 on only. Typically VLAs, so tell the compiler to treat the code as being C99 code by explcitly stating -std=c99
To #define _XOPEN_SOURCE is issued by gcc, for some header you include in your project.
Also^3 you seem to be not necessarily count the correct number of client(file)s, at least not if your files a distributed as per the archive you linked:
main.c:82
system("ls cliente* | wc -l");
Change this to be:
system("ls cliente*.txt | wc -l");
If the bug described above should return more files then there actually are the following code fails as well from a certain value of i on:
main.c:176
fd = open(nome_file, O_RDONLY);
The result of the above operation is NOT tested. The possible invalid fd is used and the infamous undefined behaviour is taking over. Everything can happen.
As a final note: It's mostly never a bug in the tools we are using.

Semaphore counter: program hangs

I want create a semaphore counter, with this code:
union semun arg_assistant;
int max_ass = atoi(argv[1]);
printf("Num massimo di assistant %d\n", max_ass);
fflush(stdout);
if ((sem_a = semget(IPC_PRIVATE, 1, 0600)) == -1) {
perror("semget");
exit(EXIT_FAILURE);
}
arg_assistant.val = max_ass;
if (semctl(sem_a, 0, SETALL, arg_assistant) == -1) {
perror("semctl");
exit(EXIT_FAILURE);
}
When I executed my program, I have no errors but it hangs and it don't create this sem. Any suggestion about what could be the problem? Have I make some mistake with falgs?
Thaks
From documentation
SETALL
Set semval for all semaphores of the set using arg.array,
For SETALL you need array of values
unsigned short int sem_array[1] ;
sem_array[0] = max_ass;
arg_assistant.array = sem_array;
if (semctl(sem_a, 0, SETALL, arg_assistant) == -1) {
perror("semctl");
exit(EXIT_FAILURE);
}
sem_array[1] becaues you create only one semaphore.

C Unix semaphores: process should wait for 0, but doesn't

have written two simple functions, one for setting a semaphore to an arbitrary value (Reset) and another one to make the process calling it wait for the semaphore to be zero:
int R(int semid, int semnum, int val) // reset
{
union semun arg;
arg.val = val;
if( semctl(sem_id,semnum,SETVAL,arg) == -1 )
{
fprintf (stderr, "Errore inizializzazione del semaforo\n%s\n",
strerror(errno) );
}
}
int Z(int semid, int semnum) // wait for zero
{
printf("waiting for zero on %d\n",semid);
struct sembuf cmd;
cmd.sem_num = semnum;
cmd.sem_op = 0;
cmd.sem_flg = 0;
if(semop(semid, &cmd, 1)<0) {ERROR}
return 0;
}
The process that is using those functions as a code that looks like this:
while(1) {
R(sem_id_counter,0,N_PROC_DEFAULT); // (N_PROC_DEFAULT=5)
/* list of tasks not having anything to do with sem_id_coutner */
Z(sem_id_counter,0);
}
What happens is that the above process just keeps executing the loop, while I want it to stop at the end, when it calls the function Z, waiting for the semaphore to become 0 before resetting it to its initial content and restart.
Where am I going wrong? Thanks [ solved: stupid typo sem_id instead of semid ]

Resources