我真的遇到了这段代码的麻烦。 我有一个缓冲区和一个方法Produce()应该是Non Blocking,这意味着当许多进程尝试生成()时,除了一个进程外,所有进程都应该返回/或失败。
我在man semop()中读到,当我们使用 IPC_NOWAIT 进程时,如果信号量已被使用,则应该失败。但这是什么意思失败?它返回一些东西?它做一个Exit()? 我真的不知道会发生什么。
在我的代码中,有时我在缓冲区中发现了2条消息,有时候会发现1条消息。 因为我正在使用IPC_NOWAIT,所以我最后应该在缓冲区中只有一条消息,因为其他进程会因为已经一起启动而失败!
以下是Produce()
代码:
msg_t* put_non_bloccante(buffer_t* buffer, msg_t* msg){
...
struct sembuf sb;
sb.sem_flg=IPC_NOWAIT;
int x=0;
sb.sem_num=VUOTE; sb.sem_op=-1;
if ((x=semop(buffer->semid, &sb,1))<0) {
printf("\n DENTROOOO DOWN%d VUOTE \n",x);/* down(VUOTE) */
perror("semop() producer down(VUOTE)");
exit(-9);
}
sb.sem_num=USO_D; sb.sem_op=-1;
if ((x=semop(buffer->semid, &sb,1))<0) { /* down(USO_D) */
printf("\n DENTROOOO DO%dWN USO D \n",x);
perror("semop() producer down(USO_D)");
exit(-10);
}
if((buffer->msg_presenti)< (buffer->size)){
/*HERE DROP THE MESSAGE IN THE BUFFER IF IS NOT FULL*/
}
sb.sem_num=USO_D; sb.sem_op= 1;
if (semop(buffer->semid, &sb,1)<0) { /* up(USO_D) */
printf("\n DENTROOOO UP USO D \n");
perror("semop() producer up(USO_D)");
exit(-11);
}
sb.sem_num=PIENE; sb.sem_op= 1;
if (semop(buffer->semid, &sb,1)<0) {
printf("\n DENTROOOO UP PIENE \n");/* up(PIENE) */
perror("semop() producer up(PIENE)");
exit(-12);
}
int delay;
delay = (int)(random() % 5 ) / 2 + 1;
sleep(delay);
}
shmdt(buffer);
shmdt(sa);
shmdt(array_msg); */
return msg;
}
这是我简单的CUNIT测试:
void test_bufferVuoto_3P_NonBlocking_Concurrently(void)
{
pid_t pid=-1;
msg_t* msg = msg_init_string("ciao");
pid_t cons_pid[3];
buffer_t* b=buffer_init(3);
int k;
for(k=0;k<3 && pid!=0;k++) {
pid = cons_pid[k]=fork();
}
switch(pid){
case -1:
printf("error fork()");
exit(-5);
break;
case 0:
buffer_attach(b->bufferid);
msg_attach(msg->msg_id);
put_non_bloccante(b,msg);
msg_deattach(msg);
buffer_deattach(b);
sleep(17);
exit(-5);
}
sleep(12);
int j=0;
for(j=0; j<3; j++) {
kill(cons_pid[j],SIGKILL); // ... and Kill processes
wait(NULL);
}
CU_ASSERT_EQUAL(b->msg_presenti,1);
CU_ASSERT(0==strcmp("ciao", (b->array_msg[0])->content) );
msg_destroy_string(msg);
buffer_destroy(b);
return;
}
我还读了一个BUG在SemOP()和IPC_NOWAIT中我不知道是否与此有关: *但这可能是不受欢迎的,因为它可以强迫 进程终止以阻止任意长时间。另一个 可能性是这样的信号量调整可以忽略 - gether(有点类似于指定IPC_NOWAIT时失败) 用于信号量操作)。 Linux采用第三种方法:减少 信号量值尽可能(即,为零)并允许 流程终止立即进行。 在内核2.6.x中,x <= 10,在某些情况下存在一个错误 防止等待信号量值变为零的进程 当价值确实变为零时被唤醒。这个bug 在内核2.6.11。*
中修复答案 0 :(得分:0)
据我所知,信号量正在按照你的要求行事,但你对应该发生的事情的概念有点偏差。
如果你使用IPC_NOWAIT并且进程无法获取信号量,那么它将立即返回-1和errno == EAGAIN。通常你会利用这段时间做别的事情,稍后再试。您可能会在持有一个或多个信号量的同时立即退出该过程。
更糟糕的是,你看起来至少有3个信号量。您减少VUOTE和USO_D,执行某些操作,然后增加USO_D和PIENE,使VUOTE锁定。这是一个错字,一个错误,还是我的误解?
总体而言,您对应该发生的事情的期望是错误的。您的代码完全有可能以1,2或3条消息结束。 (如果在持有信号量的情况下拯救,可能为0。)换句话说,根据操作系统如何安排它们,所有3个进程都可以获得信号量并成功或者只有一两个。这是不确定的。
如果真的你的意图是一个且只有一个进程可以成功,那么只需将信号量初始化为1并且永远不会增加它。获得它的第一个过程将继续进行,其余的将失败,因为它永远不会再允许任何其他过程。
修改强>
if ((x = semop(buffer->semid, &sb, 1)) < 0)
{
printf("\n DENTROOOO DOWN%d VUOTE \n", x); /* down(VUOTE) */
perror("semop() producer down(VUOTE)");
exit( -9);
}
此处 semop
调用会立即返回,如果无法获取锁定,则将x设置为-1,将errno设置为EAGAIN。 您正在对其进行编码以退出流程。您可以编写条件来执行其他操作。
if ((x = semop(buffer->semid, &sb, 1)) < 0)
{
if (errno == EAGAIN)
return NULL; //OR WHATEVER you think appropriate
else
{ //some other failure that's not EAGAIN
printf("\n DENTROOOO DOWN%d VUOTE \n", x); /* down(VUOTE) */
perror("semop() producer down(VUOTE)");
exit( -9);
}
}
//ELSE you got the lock
除了(间接)通过使用信号量之外,这些进程彼此不了解。他们每个人都将执行此代码。有些会成功,有些则不会。
这不适用于IPC_NOWAIT的原因是因为完全有可能每个进程都不必等待锁定。根据它们的预定方式,可以获得锁定并执行,然后是下一个和下一个。或者有些人会,有些则不会。无法预测。