您面臨的問題是對sem_init()
函數的誤解。當你讀了manual page 你會看到:
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);
}
}
輸出
./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
的共享變量將駐留在共享內存的同一個 區域中,從而導致影響另一個的區域發生更改。因此程序執行會變得雜亂無章。爲了避免這種情況,最好檢查一下是否返回-1(儘管我想告訴你關鍵值以防碰撞),檢查源代碼而不是像我一樣打印到屏幕。
注意如何聲明和初始化信號量。這與你在問題中所做的不同(sem_t sem
vs sem_t* sem
)。此外,你應該使用它們,因爲它們出現在這個例子中。您無法定義sem_t*
並在sem_init()
中使用它。
問題是,有些手冊頁並不那麼明確。看看SUSv2(例如):'如果pshared參數的值非爲零,則信號量在進程之間共享;在這種情況下,任何可以訪問信號量sem的進程都可以使用sem來執行sem_wait(),sem_trywait(),sem_post()和sem_destroy()操作。「要理解應該使用共享內存更加困難! – 2013-06-26 15:33:22
不幸的是,這花了我2個家庭作業才發現:)這是我認爲Linux所缺乏的:他們認爲人們已經知道事情,就好像他們是開發人員社區的一部分一樣。同樣,在我看來,它應該是解釋性的,不像那些手冊。 – Varaquilex 2013-06-26 17:51:25
我認爲你應該從子進程中分離出共享內存,就像'在fork(2)之後,孩子繼承了附加的共享內存段'(man shmdt)。 – Chris 2013-12-02 11:42:40