问题描述
我有一个主意,但我不知道该怎么做,我使用fork()从父进程创建了N个子进程。 为了使子进程一次执行一个特定的动作,我想使用一系列的信号量,将其设置为0,并将仅对应于必须执行该动作的子进程的信号量设置为1。我该怎么办? 我在c89工作。
解决方法
我为您创建了一个信号灯系统。如果您需要任何澄清,我们将很乐意回答。
这是代码:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
void fatherHandler(); //Used for acquiring the children termination statuses by the father
void resourceRequestedHandler(int sig,siginfo_t *info,void *ucontext); //Used by the father to tell any children which requested it the status of the resource
void resourceReleasedHandler(); //Used by the father to set the resource status to free when a child has finished its job
void resourceAvailable(); //Used internally by a child which requested the resource status and that found it available
void resourceUnavailable(); //Used internally by a child which requested the resource status and that found it unavailable
int n; //Number of children
int status; //The child view of the semaphore status
int semaphore; //The resource's semaphore,tells us if we can access the resource or not
int terminatedChildren; //Used by the father to know how many children has finished their job
int main(int argc,char * argv[]) {
int i; //for-loop index
int pid; //The pid of the nth child
struct sigaction sa;
i = 0;
n = 3; //For example purposes only
terminatedChildren = 0;
semaphore = 0; //The resource is not available before setup is finished
/* Use the sa_sigaction field because the handles has two additional parameters */
sa.sa_sigaction = &resourceRequestedHandler;
/* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field,not sa_handler. */
sa.sa_flags = SA_SIGINFO;
sigaction(SIGUSR1,&sa,NULL); //Used by a child to acquire the resource -> semaphore = 0
signal(SIGUSR2,resourceReleasedHandler); //Used by a child to release the resource -> semaphore = 1
signal(SIGCHLD,fatherHandler); //Used to acquire the children's termination state
/* N children are created */
while(i < n) {
pid = fork();
if (pid == 0)
i = n;
else
i++;
}
if(pid > 0) { //Father's code
semaphore = 1; //The resource becomes available
} else if(pid == 0) { //Child's code
status = 0; //The semaphore status -> not available by default
signal(SIGCHLD,SIG_DFL);
signal(SIGUSR1,resourceAvailable);
signal(SIGUSR2,resourceUnavailable);
while(!status) { //While the resource isn't available
printf("Child %d -> waiting\n",getpid()); //Demo purposes only
kill(getppid(),SIGUSR1); //The child asks the father wheter the resource has become available or not
sleep(2); //Demo purposes only
}
/*
* Here you should put the code you want every child to execute
* when they have access to the resource.
* I just do a printf();
*/
printf("Child %d did what it had to do !\n",getpid());
kill(getppid(),SIGUSR2); //The child tells the father the resource is now available again
sleep(2); //Demo purposes only
exit(1); //Child gets terminated
} else if (pid < 0) { //Fork failure
perror("Fork error:");
exit(-1);
}
for(;;); //The father just waits for its children
exit(0);
}
void resourceRequestedHandler(int sig,siginfo_t *siginfo,void *context) {
char outputMessage[200]; //Demo purposes only
int signalNumber; //The number of the signal we'll send to the child: SIGUSR1 if semaphore = 1,SIGUSR2 otherwise
int childPid = siginfo->si_pid; //We understand which child requested the semaphore status
signalNumber = (semaphore == 1) ? SIGUSR1 : SIGUSR2;
if(semaphore == 1) semaphore = 0; //If the resource was available and it's been requested it becomes unavailable: semaphore gets set to 0
sprintf(outputMessage,"Resource requested by %d,responded with resource status %d\n",childPid,signalNumber); //Demo purposes only
write(STDOUT_FILENO,outputMessage,strlen(outputMessage)); //Demo purposes only
kill(childPid,signalNumber); //We tell the child whether the resource is available or not
}
void resourceReleasedHandler() {
semaphore = 1; //If the resource is released the semaphore gets set to 1
}
void fatherHandler() {
char outputMessage[200];
int childTerminationStatus;
int childPid;
childPid = wait(&childTerminationStatus); //The father waits for the childrens' termination states
sprintf(outputMessage,"Terminated child %d with status %d\n",childTerminationStatus);
write(STDOUT_FILENO,strlen(outputMessage));
terminatedChildren++;
if(terminatedChildren == n)
exit(0); //All children terminated
}
void resourceAvailable() {
char outputMessage[200]; //Demo purposes only
sprintf(outputMessage,"Child %d -> resource Available\n",getpid()); //Demo purposes only
write(STDOUT_FILENO,strlen(outputMessage)); //Demo purposes only
status = 1;
}
void resourceUnavailable() {
char outputMessage[200]; //Demo purposes only
sprintf(outputMessage,"Child %d -> resource Unavailable\n",strlen(outputMessage)); //Demo purposes only
status = 0;
}
注意:由于Linux在短时间内处理多个信号的方式,因此代码中的任何sleep()
都在那里。如果您不需要打印任何内容,则可以忽略它们。
如果要快速测试该解决方案,这是一个在线C编译器,只需将代码粘贴到此处并点击“运行”即可:https://repl.it/languages/c
这可能是一个更优雅的解决方案:https://www.geeksforgeeks.org/use-posix-semaphores-c/