你面临的问题是误解sem_init()
功能。当你读到手册页你会看到这个:
pshared 参数指示是否共享该信号量
进程的线程之间或进程之间。
如果您读完到目前为止,您会认为 pshared 的非零值将使信号量成为进程间信号量。然而,这是错误的。
您应该继续阅读,您将了解必须在共享内存区域中找到信号量。为此,可以使用几个函数
你可以看到下面:
如果 pshared 非零,则信号量在进程之间共享,
并且应该位于共享内存区域(参见 shm_open(3),
mmap(2) 和 shmget(2))。 (因为 fork(2) 创建的子进程继承了
它的父级内存映射,它也可以访问信号量。)任何
可以访问共享内存区域的进程可以在
使用 sem_post(3)、sem_wait(3) 等信号量
我发现这种方法比其他方法更复杂,因此我想鼓励人们使用sem_open()
代替sem_init()
.
下面你可以看到一个完整的程序说明如下:
- 如何在分叉之间分配共享内存和使用共享变量
流程。
- 如何在共享内存区域中初始化信号量并使用
通过多个进程。
- 如何分叉多个进程并让父进程等待所有进程
它的孩子退出。
#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);
}
}
OUTPUT
./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()
函数多次失败,共享变量具有shmkey
有价值-1
将居住在同一个地方
共享内存区域的变化会导致一个区域的变化影响另一个区域。因此程序的执行会变得混乱。为了避免这种情况,最好检查是否ftok()
返回 -1 或不返回(最好检查源代码而不是像我一样打印到屏幕,尽管我想向您显示键值以防发生冲突)。
注意信号量是如何声明和初始化的。这与您在问题中所做的不同(sem_t sem
vs sem_t* sem
)。此外,您应该按照本示例中的显示方式使用它们。你无法定义sem_t*
并用在sem_init()
.