C-->如何使用信号量协调进程行为?
C-->How to coordinate processes behaviour using semaphore?
想请大家帮忙理解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 开始之前完成他的代码要求的一切?
谢谢:)
您的问题不清楚 - 最好清楚地说明您观察到的问题。由于该程序正在尝试同步父项和子项并且您询问了这一点,我假设您看到父项试图在子项通过信号量发出完成信号之前阅读消息。
正如 Fred 所说,您没有初始化 sysV 信号量;完成后也不要删除它 (this may help)。我假设信号量(如果尚不存在)从值 0 开始。由于它是一个 IPC 工具并且不属于任何单个进程,因此它在运行之间持续存在。
您的程序(我们可以看到)调用 semaphoreSignal
两次和 semaphoreWait
一次,因此每次程序运行时它都会将信号量的值递增 1 并保持原样;因此在后续运行中,由于先前运行的剩余值,信号量值开始 >0,因此父级立即运行。
您还应该检查 ftok(3) 的 return 值; /temp
不是通常存在的路径。
想请大家帮忙理解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 开始之前完成他的代码要求的一切?
谢谢:)
您的问题不清楚 - 最好清楚地说明您观察到的问题。由于该程序正在尝试同步父项和子项并且您询问了这一点,我假设您看到父项试图在子项通过信号量发出完成信号之前阅读消息。
正如 Fred 所说,您没有初始化 sysV 信号量;完成后也不要删除它 (this may help)。我假设信号量(如果尚不存在)从值 0 开始。由于它是一个 IPC 工具并且不属于任何单个进程,因此它在运行之间持续存在。
您的程序(我们可以看到)调用 semaphoreSignal
两次和 semaphoreWait
一次,因此每次程序运行时它都会将信号量的值递增 1 并保持原样;因此在后续运行中,由于先前运行的剩余值,信号量值开始 >0,因此父级立即运行。
您还应该检查 ftok(3) 的 return 值; /temp
不是通常存在的路径。