C -> Как координировать поведение процессов с помощью семафора? - PullRequest
0 голосов
/ 31 декабря 2018

Я бы хотел попросить вас, ребята, помочь с пониманием C Semaphores.В основном я хочу создать два процесса Child и Parent.Конечно, их поведение отличается:

1) Дочерний процесс выполняет некоторые действия sleep() и отправляет сообщение в ранее созданную очередь сообщений

2) Родительский процесс также выполняет некоторые операции sleep(), но затемчитает сообщение, отправленное в очередь.

Мне нужен, конечно, дочерний процесс, чтобы запускаться первым.Мне удалось сделать это с помощью системных вызовов wait и waitpid, и теперь я хотел бы сделать это с помощью Semaphore.Ниже приведен код, который мне удалось написать:

A) Функции, которые я использую с 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) Функции, которые я использую с 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) Наконец-то мой main.c файл:

#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);
    }
}

Как вы, ребята, заметили, процессы Child и Parent не синхронизируются в этом файле main.c, как мне хотелось бы,Мой вопрос: как я могу убедиться, что Child выполняет все, что требует его код, до запуска Parent?Спасибо :)

1 Ответ

0 голосов
/ 31 декабря 2018

Ваш вопрос не ясен - лучше четко изложить проблему, которую вы наблюдали.Так как программа пытается синхронизировать родитель и потомок, и вы спрашиваете об этом, я предполагаю, что вы видите, как родитель пытается прочитать сообщение до того, как ребенок сообщил о завершении через семафор.

Как отмечает Фред,вы не инициализируете семафор sysV;Вы также не удаляете его, когда закончите ( это может помочь ).Я предполагаю, что семафор, если он еще не существует, начинается со значения 0. Так как это инструмент IPC и не принадлежит ни одному отдельному процессу, он сохраняется между запусками.

Ваша программа (что мы можем видетьиз него) вызывает semaphoreSignal дважды и semaphoreWait один раз, поэтому каждый раз, когда программа запускается, она увеличивает значение семафора на 1 и оставляет его таким образом;поэтому при последующих запусках значение семафора начинается> 0 из-за оставшегося значения от предыдущих запусков, поэтому родительский прогон запускается немедленно.

Также вы должны проверить возвращаемое значение ftok (3);/temp обычно путь не существует.

...