I'd like to ask you guys for some help in understanding C Semaphores
.
Basically I want to create two Processes Child
and Parent
.
Of course their behaviour is different:
1) Child Process does some sleep()
and sends a Message on a previously created Message Queue
2) Parent Process does some sleep()
too but then reads the Message sent on the Queue.
I need Child Process to be first one to run, of course.
I managed to do this using wait
and waitpid
system calls, and now I would like to do it using Semaphore
.
Below some code I managed to write:
A) Functions I'm using from semaphore.h
//In order to create a Semaphore
int createSemaphore(key_t semaphoreKey){
int semaphoreId = semget(semaphoreKey, 1, 0666 | IPC_CREAT);
if(semaphoreId == -1){
printf(RED "Semaphore Creation failed\n"RESET);
return -1;
}
return semaphoreId;
}
void semaphoreWait(int semaphoreId, int semaphoreNumber){
struct sembuf buffer;
buffer.sem_num = semaphoreNumber;
buffer.sem_op = -1;
buffer.sem_flg = 0;
int done = semop(semaphoreId, &buffer, 1);
if(done == -1){
printf(RED "Wait on Semaphore %d failed\n" RESET, semaphoreNumber);
return;
}
}
void semaphoreSignal(int semaphoreId, int semaphoreNumber){
struct sembuf buffer;
buffer.sem_num = semaphoreNumber;
buffer.sem_op = 1;
buffer.sem_flg = 0;
int done = semop(semaphoreId, &buffer, 1);
if(done == -1){
printf(RED "semaphoreSignal Failed on Semaphore %d\n" RESET, semaphoreNumber);
return;
}
}
B) Functions I'm using from messageQueue.h
typedef struct message{
long type;
char text[255];
}message;
//Creates a Message Queue and returns its ID
int createMessageQueue(key_t semaphoreKey){
int queueId;
queueId = msgget(semaphoreKey, 0666 | IPC_CREAT);
return queueId;
}
//Sends a Message on Message Queue queueId
void sendMessage(int queueId, message* messaggio){
int sent = msgsnd(queueId, messaggio, strlen(messaggio->text) + 1, 0);
if(sent == -1){
printf(RED "Sending the message %s failed on Message Queue %d\n"RESET, messaggio->text, queueId);
return;
}
}
//Receives a message from Message Queue queueId
void receiveMessage(int queueId, message* messaggio, int type){
int received = msgrcv(queueId, messaggio, 255, type, 0);
if(received == -1){
printf(RED "Receiving message on Message Queue %d failed\n" RESET, queueId);
return;
}
}
void setText(message *mex, char text[], int size){
for(int i = 0; i < size; i++){
mex->text[i] = text[i];
}
}
C) At last my main.c
file:
#include "semaphore.h"
#include "messageQueue.h"
int main(int argc, char *argv[]){
pid_t piddo;
message mex, mex2;
mex2.type = 1;
key_t semKey = ftok("/temp", 0);
key_t mexKey = ftok("/temp", 1);
char text[] = "This is a message sent from Child to Parent";
int semId = createSemaphore(semKey);
int mexId = createMessageQueue(mexKey);
switch(piddo = fork()){
case -1:
printf(RED "Fork ERROR\n" RESET);
exit(EXIT_FAILURE);
case 0:
printf(CYAN "Child Process %d has started\n" RESET, getpid());
printf(CYAN "Doing some useless sleep\n" RESET);
for(int i = 0; i < 4; i++){
printf(CYAN "Sleep %d\n" RESET, i);
sleep(1);
}
printf(CYAN "Useless Sleep Finished\n" RESET);
printf(CYAN "Now I setup Message to send\n" RESET);
mex.type = 1;
setText(&mex, text, strlen(text));
printf(CYAN "Settings saved, Now I send Message\n" RESET);
sendMessage(mexId, &mex);
printf(CYAN "Message succesfully sent, Child Process %d has finished\n" RESET, getpid());
//Now I want Parent Process to know Child has finished
semaphoreSignal(semId, 0);
exit(EXIT_SUCCESS);
default:
printf(YELLOW "Parent Process %d started\n" RESET, getpid());
printf(YELLOW "I have to wait for Child Process\n" RESET);
//With this wait Parent Process should wait for Child to have finished
semaphoreWait(semId, 0);
//Now Parent knows Child has finished
printf(YELLOW "Looks like Child Process has finished\n" RESET);
printf(YELLOW "Doing some useless sleep\n" RESET);
for(int i = 0; i < 4; i++){
printf(YELLOW "Sleep %d\n" RESET, i);
sleep(1);
}
printf(YELLOW "Useless sleep finished\n" RESET);
printf(YELLOW "Receiving Message sent by Child...\n" RESET);
receiveMessage(mexId, &mex2, 1);
printf(YELLOW "Message Received: \n" RESET);
printf(YELLOW "%s\n" RESET, mex2.text);
printf(YELLOW "All Done, Parent Process %d has finished\n" RESET, getpid());
semaphoreSignal(semId, 0);
exit(EXIT_SUCCESS);
}
}
As you guys may notice, Child
and Parent
processes are not synchronized in this main.c
file as I would like.
My question is:
How can I make sure Child does everything his code demands before Parent starts?
Thank you :)
Your question isn't clear - it's best to clearly state the problem that you observed. Since the program is trying to synchronise the parent and child and you ask about that, I assume you're seeing the parent trying to read the message before the child has signalled completion via the semaphore.
As Fred notes, you aren't initialising the sysV semaphore; you also don't delete it when you are done (this may help). I assume that the semaphore, if it doesn't already exist, starts with value 0. Since it's a IPC tool and not owned by any single process, it persists between runs.
Your program (what we can see of it) calls semaphoreSignal
twice and semaphoreWait
once, so each time the program runs it increments the value of the semaphore by 1 and leaves it that way; so on subsequent runs the semaphore value starts >0 due to the leftover value from previous runs and so the parent runs immediately.
Also you should check the return value of ftok(3); /temp
isn't a path that normally exists.