我想派生多个进程,然后在它们上使用一个信号灯。这是我尝试过的:
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); }
输出为:
孩子(0)分叉 孩子(1)分叉 Child(0)在关键部分。 Child(1)在关键部分。 孩子(2)分叉 Child(2)在关键部分。 孩子(3)分叉 Child(3)在关键部分。 孩子(4)分叉 Child(4)在关键部分。 Child(0)新值* p = 0。 Child(1)新值* p = 1。 Child(2)的新值* p = 3。 Child(3)的新值* p = 3。 Child(4)的新值* p = 4。 父母:所有孩子都退出了。
显然,这意味着信号灯没有按预期的方式工作。您能解释一下我应该如何在分支进程中使用信号量?
您面临的问题是对sem_init()功能的误解。阅读手册页时, 您将看到以下内容:
sem_init()
pshared参数指示此信号量是在进程的线程之间还是在进程之间共享。
如果您到此为止都读完了,您将认为pshared的非零值将使信号量成为进程间信号量。但是,这是错误的。您应该继续阅读,您将了解到必须在共享内存区域中找到信号灯。为此,可以使用几个功能,如下所示:
如果pshared为非零,则信号量在进程之间共享,并且应位于共享内存的区域中(请参见shm_open(3),mmap(2)和shmget(2))。(由于fork(2)创建的子级继承了其父级的内存映射,因此它也可以访问该信号量。)任何可以访问共享内存区域的进程都可以使用sem_post(3),sem_wait(3)等对该信号量进行操作。 。
我发现这种方法比其他方法更为复杂,因此我想鼓励人们使用sem_open()而不是sem_init()。
sem_open()
在下面您可以看到一个完整的程序,说明了以下内容:
如何派生多个进程并使父级等待所有子级退出。
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()函数多次失败,则具有shmkeywith值的共享变量-1将驻留在共享内存的同一区域中,从而导致一个更改影响另一个。因此,程序执行将变得混乱。为了避免这种情况,最好检查是否ftok() 返回-1(最好是签入源代码,而不是像我一样打印到屏幕上,尽管我想向您显示键值以防发生冲突)。
shmkey
ftok()
-1
请注意如何声明和初始化信号量。它与您在问题(sem_t semvs sem_t* sem)中所做的不同。此外,您应该使用它们在本示例中显示的形式。您不能在中定义sem_t*和使用它sem_init()。
sem_t sem
sem_t* sem
sem_t*