Var*_*lex 22 c linux fork semaphore shared-memory
我想分叉多个进程,然后在它们上使用信号量.这是我尝试过的:
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);
}
Run Code Online (Sandbox Code Playgroud)
输出是:
child(0) forked child(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.
这显然意味着信号量不能像预期的那样工作.你能解释一下我应该如何在分叉进程上使用信号量?
Var*_*lex 61
你面临的问题是对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);
}
}
Run Code Online (Sandbox Code Playgroud)
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.
Run Code Online (Sandbox Code Playgroud)
检查是不错的,shmkey因为ftok()失败时返回-1.但是,如果您有多个共享变量,并且该ftok()函数多次失败,则具有shmkeywith值的共享变量-1将驻留在共享内存的同一区域中,从而导致一个变化影响另一个.因此程序执行会变得混乱.为了避免这种情况,最好检查是否ftok()
返回-1(更好地检查源代码而不是像我一样打印到屏幕,尽管我想在出现碰撞时向您显示关键值).
注意声明和初始化信号量的方式.它与您在问题中所做的不同(sem_t semvs sem_t* sem).此外,您应该使用它们在此示例中出现.您无法定义sem_t*和使用它sem_init().
| 归档时间: |
|
| 查看次数: |
44890 次 |
| 最近记录: |