gpt4 book ai didi

c - IPC_NOWAIT semop() 缓冲区 SysV 进程

转载 作者:行者123 更新时间:2023-11-30 17:42:07 25 4
gpt4 key购买 nike

这段代码我真的遇到了麻烦。我有一个缓冲区和一个方法 Produce() ,它应该是非阻塞的,这意味着当许多进程尝试 Produce() 时,除了一个进程之外,所有这些进程都应该返回/或失败。

我在 man semop() 中读到,当我们使用 IPC_NOWAIT 时,如果信号量已在使用中,进程应该失败。但这意味着失败是什么意思?它返回一些东西?它执行 Exit() 吗?我真的不知道会发生什么。

在我的代码中,有时我在缓冲区中发现 2 条消息,有时发现 1 条消息。由于我使用的是 IPC_NOWAIT,因此缓冲区中最后应该只有 1 条消息,因为其他进程应该会失败,因为它们是一起启动的!

这是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;
}

我还在 Man of SemOP() 和 IPC_NOWAIT 中读到了一个 BUG,我不知道是否与此相关:*然而这是不可取的,因为它可能会迫使 进程终止以阻塞任意长时间。其他 可能性是这样的信号量调整可以被忽略 gether(有点类似于指定 IPC_NOWAIT 时失败 用于信号量操作)。 Linux采用第三种方法:减少 信号量值尽可能(即为零)并允许 进程终止立即继续。 在内核 2.6.x 中,x <= 10,存在一个错误,在某些情况下 防止进程等待信号量值变为零 当该值实际上变为零时被唤醒。这个错误 已在内核 2.6.11.* 中修复

最佳答案

据我所知,信号量正在按照您的要求进行操作,但您对应该发生的情况的概念有点偏差。

如果您使用 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 的原因是因为每个进程完全有可能不必等待锁定。根据它们的调度方式,一个可能会获得锁定并执行,然后是下一个和下一个。或者有些会,有些不会。这是不可能预测的。

关于c - IPC_NOWAIT semop() 缓冲区 SysV 进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20802415/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com