IPC_NOWAIT semop()缓冲SysV进程

时间:2013-12-27 14:30:53

标签: c process ipc semaphore shared-memory

我真的遇到了这段代码的麻烦。 我有一个缓冲区和一个方法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。*

中修复

1 个答案:

答案 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的原因是因为完全有可能每个进程都不必等待锁定。根据它们的预定方式,可以获得锁定并执行,然后是下一个和下一个。或者有些人会,有些则不会。无法预测。