fork 後父子進程擁有獨立地址空間,為何對同一信號量的 PV 操作能相互影響?
信號量是內核對象,而非進程私有數據。
semget() 或 sem_open() 創建信號量時,內核在系統維護的信號量表中分配條目,返回系統級標識符(ID 或指針)。semop()、sem_wait()/sem_post())是系統調用,直接操作內核中的信號量值,因此對所有持有該標識符的進程可見。像文件描述符:fork 後父子進程持有相同的 fd 數值,讀寫同一文件偏移量會互相影響。信號量同理,內核保證原子性與共享性。
// 父進程創建
int semid = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
semctl(semid, 0, SETVAL, 0); // 初始值 0
if (fork() == 0) {
// 子進程 P 操作
struct sembuf p = {0, -1, 0};
semop(semid, &p, 1); // 阻塞,因值為 0
printf("child got semaphore\n");
} else {
sleep(1);
// 父進程 V 操作
struct sembuf v = {0, 1, 0};
semop(semid, &v, 1); // 釋放,子進程繼續
wait(NULL);
}
輸出證明子進程阻塞於 P,父進程 V 後子進程繼續,雙方操作同一內核信號量。