通过unix ME和计数器信号量同步系统

时间:2013-12-03 16:58:46

标签: c unix synchronization semaphore synchronized

我很难处理同步问题。 我目前的架构需要像这样:

N个工作流程在共享的内存段上互斥。 当所有人完成工作后,1“屏幕”进程显示共享内存状态

N个进程的工作顺序无关紧要,它们都是相同的,但它们都需要在共享内存上工作ONCE(之后)“屏幕”进程完成了他的工作(因此在相互作用中)也被排除在外。)

我想过组织这样的流程: 我创建了两个信号量,一个用于互斥的二进制(1或0)和一个用作计数器的信号(它的值可以从0到#进程)。

我将使用标准字母表示对信号量的标准操作:

P&P; V是传统的等待和信号

Z(sem)=在sem上等待零(仅在sem_counter上使用)

R(sem)=重置sem(仅用于sem_counter)

这是在信号量上运行的公共函数的代码:

int P(int semid, int semnum)    // signal
{
        struct sembuf cmd;
        cmd.sem_num = semnum;
        cmd.sem_op = -1;
        cmd.sem_flg = 0;
        semop(semid, &cmd, 1);
        return 1;

}


int V(int semid, int semnum)    // wait
{
        struct sembuf cmd;
        cmd.sem_num = semnum;
        cmd.sem_op = 1;
        cmd.sem_flg = 0;
        semop(semid, &cmd, 1);
        return 0;
}

int Z(int semid, int semnum)    // wait for zero
{
        struct sembuf cmd;
        cmd.sem_num = semnum;
        cmd.sem_op = 0;
        cmd.sem_flg = 0;
        if(semop(semid, &cmd, 1) < 0)
        {
            fprintf (stderr, "Errore inizializzazione del semaforo\n%s\n",
                strerror(errno) );

        }
        return 0;
}

int R(int semid, int semnum, int val)   // reset
{

    union semun arg;
    arg.val = val;
    if( semctl(semid,semnum,SETVAL,arg) == -1 )  
    {
        fprintf (stderr, "Errore inizializzazione del semaforo\n%s\n",
                strerror(errno) );
    }
}

这是重置计数器信号量的“显示”过程的代码:

while( 1 )
{

    printf("Initialization \n");

    // signal ME semaphore
    inuso = P(sem_id,0);

    printf("Doing work on the shared memory \n");

    //  reset counter semaphore
    R(sem_id_counter,0,N_PROC_DEFAULT);

    printf("Again doing work on the shared memory \n");

    // release ME semaphore
    inuso = V(sem_id,0);

    // wait for sem counter to become 0
    Z(sem_id_counter,0); 

}

这是减少反信号量的工作过程的代码:

while(1)
{

// try to diminish counter semaphore
P(sem_id_counter,0);

// asks for ME semaphore
inuso=P(sem_id,0);

printf("Doing stuff on the shared memory");

// releases ME semaphore
inuso=V(sem_id,0);

// waits for other processes to finish (4 sem_counter 2 become 0)
Z(sem_id_counter,0);

}

问题是他们最终会被困住;如果我从“工作过程”中删除Z(即我不会让他们在再次尝试之前等待其他人),就不会发生这种情况。

1 个答案:

答案 0 :(得分:2)

  

问题在于它们最终会卡住

考虑这一事件:

  • 最后一个工作流程刚从P(sem_id_counter,0);返回,使得计数器信号量的值为
  • 现在&#34;显示&#34;进程已准备好运行并立即执行从

    返回
    Z(sem_id_counter,0);
    

    以及

    printf("Initialization \n");
    inuso = P(sem_id,0);
    

    在工作流程执行P(sem_id,0);之前阻止工作流程,直到计数器信号量重置为N_PROC_DEFAULT,比如 5

  • 之后,由于上述工作流程已经通过Z(),其他正在等待的工作流程将计数器信号量减少到不小于 1 。 {1}}
  • 最后,所有进程都等待计数器信号量达到,这永远不会发生。

实际上,只要计数器信号量可以重置为P(sem_id_counter,0);而没有每个工作进程等待或已经等待计数,就会发生类似的死锁。确保不会发生这种情况的一种方法是测试(在#34;显示&#34;流程循环的开始)等待增加 semval 的进程数量N_PROC_DEFAULT,仅在该号码为P(sem_id_counter,0)之后继续:

N_PROC_DEFAULT

或者,如果您不想轮询工作人员,可以使 // wait until all workers are waiting in P(sem_id_counter,0) struct timespec req = { 0, 100000000 }; // 0.1 s while (semctl(sem_id_counter, 0, GETNCNT) < N_PROC_DEFAULT) nanosleep(&req, NULL); printf("Initialization \n"); … 包含2个信号量的数组,并使用额外的计数信号量来表示工作人员等待 0 在主要柜台上,i。即

    sem_id_counter中的
  • 将两个计数器设置为R() cmd N_PROC_DEFAULT

  • 在&#34;显示&#34;结束时流程循环执行SETALL而不是Z(sem_id_counter, 1)

  • 在工作流程循环结束时执行Z(…, 0)