gpt4 book ai didi

c - 如何在 C 中的 fork 进程上使用 POSIX 信号量?

转载 作者:太空宇宙 更新时间:2023-11-04 11:55:44 24 4
gpt4 key购买 nike

我想 fork 多个进程,然后对它们使用信号量。这是我尝试过的:

sem_init(&sem, 1, 1);   /* semaphore*, pshared, value */
.
.
.
if(pid != 0){ /* parent process */
wait(NULL); /* wait all child processes */

printf("\nParent: All children have exited.\n");
.
.
/* cleanup semaphores */
sem_destroy(&sem);
exit(0);
}
else{ /* child process */
sem_wait(&sem); /* P operation */
printf(" Child(%d) is in critical section.\n",i);
sleep(1);
*p += i%3; /* increment *p by 0, 1 or 2 based on i */
printf(" Child(%d) new value of *p=%d.\n",i,*p);
sem_post(&sem); /* V operation */
exit(0);
}

输出是:

child(0) forkedchild(1) forked  Child(0) is in critical section.  Child(1) is in critical section.child(2) forked  Child(2) is in critical section.child(3) forked  Child(3) is in critical section.child(4) forked  Child(4) is in critical section.  Child(0) new value of *p=0.  Child(1) new value of *p=1.  Child(2) new value of *p=3.  Child(3) new value of *p=3.  Child(4) new value of *p=4.Parent: All children have exited.

这显然意味着信号量没有按预期工作。你能解释一下我应该如何在 fork 进程上使用信号量吗?

最佳答案

您遇到的问题是对sem_init()函数的误解。当您阅读 manual page你会看到这个:

The pshared argument indicates whether this semaphore is to be shared between the threads of a process, or between processes.

如果你读到这里,你会认为 pshared 的非零值会使信号量成为进程间信号量。然而,这是错误的。您应该继续阅读,您将了解到必须在共享内存区域中定位信号量。为此,可以使用几个函数作为你可以在下面看到:

If pshared is nonzero, then the semaphore is shared between processes, and should be located in a region of shared memory (see shm_open(3), mmap(2), and shmget(2)). (Since a child created by fork(2) inherits its parent's memory mappings, it can also access the semaphore.) Any process that can access the shared memory region can operate on the semaphore using sem_post(3), sem_wait(3), etc.

我发现这种方法比其他方法更复杂,因此我想鼓励人们使用 sem_open() 而不是 sem_init()

下面你可以看到一个完整的程序说明如下:

  • 如何在fork之间分配共享内存和使用共享变量流程。
  • 如何在共享内存区域中初始化信号量并使用由多个进程。
  • 如何 fork 多个进程并让父进程等到所有进程它的 child 退出。
#include <stdio.h>          /* printf()                 */
#include <stdlib.h> /* exit(), malloc(), free() */
#include <sys/types.h> /* key_t, sem_t, pid_t */
#include <sys/shm.h> /* shmat(), IPC_RMID */
#include <errno.h> /* errno, ECHILD */
#include <semaphore.h> /* sem_open(), sem_destroy(), sem_wait().. */
#include <fcntl.h> /* O_CREAT, O_EXEC */


int main (int argc, char **argv){
int i; /* loop variables */
key_t shmkey; /* shared memory key */
int shmid; /* shared memory id */
sem_t *sem; /* synch semaphore *//*shared */
pid_t pid; /* fork pid */
int *p; /* shared variable *//*shared */
unsigned int n; /* fork count */
unsigned int value; /* semaphore value */

/* initialize a shared variable in shared memory */
shmkey = ftok ("/dev/null", 5); /* valid directory name and a number */
printf ("shmkey for p = %d\n", shmkey);
shmid = shmget (shmkey, sizeof (int), 0644 | IPC_CREAT);
if (shmid < 0){ /* shared memory error check */
perror ("shmget\n");
exit (1);
}

p = (int *) shmat (shmid, NULL, 0); /* attach p to shared memory */
*p = 0;
printf ("p=%d is allocated in shared memory.\n\n", *p);

/********************************************************/

printf ("How many children do you want to fork?\n");
printf ("Fork count: ");
scanf ("%u", &n);

printf ("What do you want the semaphore value to be?\n");
printf ("Semaphore value: ");
scanf ("%u", &value);

/* initialize semaphores for shared processes */
sem = sem_open ("pSem", O_CREAT | O_EXCL, 0644, value);
/* name of semaphore is "pSem", semaphore is reached using this name */

printf ("semaphores initialized.\n\n");


/* fork child processes */
for (i = 0; i < n; i++){
pid = fork ();
if (pid < 0) {
/* check for error */
sem_unlink ("pSem");
sem_close(sem);
/* unlink prevents the semaphore existing forever */
/* if a crash occurs during the execution */
printf ("Fork error.\n");
 }
else if (pid == 0)
break; /* child processes */
}


/******************************************************/
/****************** PARENT PROCESS ****************/
/******************************************************/
if (pid != 0){
/* wait for all children to exit */
while (pid = waitpid (-1, NULL, 0)){
if (errno == ECHILD)
break;
}

printf ("\nParent: All children have exited.\n");

/* shared memory detach */
shmdt (p);
shmctl (shmid, IPC_RMID, 0);

/* cleanup semaphores */
sem_unlink ("pSem");
sem_close(sem);
/* unlink prevents the semaphore existing forever */
/* if a crash occurs during the execution */
exit (0);
}

/******************************************************/
/****************** CHILD PROCESS *****************/
/******************************************************/
else{
sem_wait (sem); /* P operation */
printf (" Child(%d) is in critical section.\n", i);
sleep (1);
*p += i % 3; /* increment *p by 0, 1 or 2 based on i */
printf (" Child(%d) new value of *p=%d.\n", i, *p);
sem_post (sem); /* V operation */
exit (0);
}
}

输出

./a.out 
shmkey for p = 84214791
p=0 is allocated in shared memory.

How many children do you want to fork?
Fork count: 6
What do you want the semaphore value to be?
Semaphore value: 2
semaphores initialized.

Child(0) is in critical section.
Child(1) is in critical section.
Child(0) new value of *p=0.
Child(1) new value of *p=1.
Child(2) is in critical section.
Child(3) is in critical section.
Child(2) new value of *p=3.
Child(3) new value of *p=3.
Child(4) is in critical section.
Child(5) is in critical section.
Child(4) new value of *p=4.
Child(5) new value of *p=6.

Parent: All children have exited.

检查 shmkey 还不错,因为当 ftok() 失败时,它会返回 -1。但是,如果您有多个共享变量并且如果 ftok() 函数多次失败,具有值为 -1shmkey 的共享变量将驻留在同一个共享内存的区域导致一个影响另一个的变化。因此程序执行会变得困惑。为避免这种情况,最好检查 ftok()是否返回 -1(最好 checkin 源代码而不是像我那样打印到屏幕,尽管我想向您展示键值以防发生冲突)。

注意信号量是如何声明和初始化的。这与您在问题中所做的不同(sem_t sem vs sem_t* sem)。此外,您应该按照本例中出现的方式使用它们。您不能定义 sem_t* 并在 sem_init() 中使用它。

关于c - 如何在 C 中的 fork 进程上使用 POSIX 信号量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54418826/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com