简体   繁体   English

C->如何使用信号量协调流程行为?

[英]C-->How to coordinate processes behaviour using semaphore?

I'd like to ask you guys for some help in understanding C Semaphores . 我想请大家帮忙了解C Semaphores Basically I want to create two Processes Child and Parent . 基本上,我想创建两个Process ChildParent Of course their behaviour is different: 当然,他们的行为是不同的:

1) Child Process does some sleep() and sends a Message on a previously created Message Queue 1)子进程执行sleep()并在先前创建的消息队列上发送消息

2) Parent Process does some sleep() too but then reads the Message sent on the Queue. 2)父进程也执行了sleep()但是读取了队列中发送的消息。

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 . 我设法使用waitwaitpid系统调用来做到这一点,现在我想使用Semaphore来做到这一点。 Below some code I managed to write: 在我设法编写的一些代码下面:

A) Functions I'm using from semaphore.h 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) Functions I'm using from messageQueue.h 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) At last my main.c file: 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);
    }
}

As you guys may notice, Child and Parent processes are not synchronized in this main.c file as I would like. 你们可能已经注意到, Child进程和Parent进程在这个main.c文件中并不像我所希望的那样同步。 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; 正如Fred所指出的,您不是在初始化sysV信号量。 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. 我假设该信号量(如果尚不存在)以值0开头。由于它是IPC工具,不属于任何单个进程,因此它在两次运行之间仍然存在。

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; 你的程序(我们可以看到它)调用semaphoreSignal两次semaphoreWait一次,所以每次程序运行时,它的时间由1递增信号量的值,并留下这样说。 so on subsequent runs the semaphore value starts >0 due to the leftover value from previous runs and so the parent runs immediately. 因此在后续运行中,由于前一次运行的剩余值,信号量值开始> 0,因此父级立即运行。

Also you should check the return value of ftok(3); 您还应该检查ftok(3)的返回值; /temp isn't a path that normally exists. /temp不是通常存在的路径。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM