【问题标题】:POSIX implementation of a named semaphore for IPC用于 IPC 的命名信号量的 POSIX 实现
【发布时间】:2020-03-20 06:37:57
【问题描述】:

我正在处理一项家庭作业,其中涉及实施信号量以强制子进程之间的互斥。我的大部分代码都在工作,除了我没有正确使用信号量。我发现的文章没有多大帮助。有人可以向我解释一下 POSIX 信号量是如何工作的吗?

例如,如果我有一个父进程使用fork()execl() 派生子进程:

sem=sem_open("/semaphore1",O_CREAT|O_EXCL,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,1);
for (i = 0; i < 3; i++) 
    {
        //three child process are spawned in the image of the parent
        child[i] = fork();

        //establish whether all children were created successfully
        switch (child[i]) 
        {
            //child process creation failed...
            case -1:
                rpterror ((char *)"fork failure", pname);
                exit(1);
            //given that the fork() was successful (the children were spawned successfully)...
            case 0:
                sprintf (pname, "shmc%d", i+1);
                execl("shmc1", pname, ascshmid, (char *)0);
                perror ("execl failed");
                exit (2);
        }
    }

并且孩子想要访问和修改共享内存段(由父创建)中的值:

sem=sem_open("/semaphore1", O_RDWR);
while ( !all_out) 
{       /* loop to sell all seats */

    /* puts the process to sleep for an amount of time, then decreases the amount of seats available. Before printing out the new count of seats, the process sleeps again. Finally, it prints the seat count until there are no more seats left.*/
    if (class_ptr->seats_left > 0) 
    {
        sem_wait(sem);
        sleep ( (unsigned)rand()%5 + 1);
        class_ptr->seats_left--;
        sleep ( (unsigned)rand()%5 + 1);
        cout << pname << " SOLD SEAT -- "  << class_ptr->seats_left << " left" <<endl;
        sem_post(sem);
    }

    else
    {
        all_out++;
        cout << pname << " sees no seats left" << endl;
    }
    sleep ( (unsigned)rand()%10 + 1);
}

其中seats_left 是共享变量。

运行此代码会给我一个如下所示的输出。共享变量的初始值为 15:

shmc1 SOLD SEAT -- 14 left
shmc2 SOLD SEAT -- 13 left
shmc3 SOLD SEAT -- 12 left
shmc1 SOLD SEAT -- 11 left
shmc2 SOLD SEAT -- 10 left
shmc3 SOLD SEAT -- 9 left
shmc1 SOLD SEAT -- 8 left
shmc2 SOLD SEAT -- 7 left
shmc3 SOLD SEAT -- 6 left
shmc2 SOLD SEAT -- 5 left
shmc1 SOLD SEAT -- 4 left
shmc3 SOLD SEAT -- 3 left
shmc2 SOLD SEAT -- 2 left
shmc1 SOLD SEAT -- 1 left
shmc1 sees no seats left
shmc3 SOLD SEAT -- 0 left
shmc3 sees no seats left
shmc2 SOLD SEAT -- -1 left
shmc2 sees no seats left
Parent removing shm

如您所见,最后是我的进程在另一个进程进入临界区的同时进入临界区的地方。有谁知道这是为什么?

【问题讨论】:

    标签: linux posix ipc semaphore


    【解决方案1】:

    尝试将sem_wait() 移到if 语句之外:

    sem=sem_open("/semaphore1", O_RDWR);
    while (!all_out) {
      sem_wait(sem);
      if (class_ptr->seats_left > 0)  {
        sleep((unsigned)rand()%5 + 1);
        class_ptr->seats_left--;
        sleep((unsigned)rand()%5 + 1);
        cout << pname << " SOLD SEAT -- "  << class_ptr->seats_left << " left" <<endl;
      }
      else {
        all_out++;
        cout << pname << " sees no seats left" << endl;
      }
      sem_post(sem);
      sleep((unsigned)rand()%10 + 1);
    }
    

    我不认为您对不尊重关键部分的流程有问题(尽管信号量是一种荣誉系统,就像普通的停车灯一样......)。我认为问题只是进程B 正在等待锁,它由进程A 持有,当A 卖掉最后一张票并释放锁时,B 抓住锁并卖掉另一张票,因为它已经检查了门票是否可用,并且在售出最后一张之前不再检查。

    如果您运行此程序的次数足够多,您可能会看到零票、一张票和两张票被超卖的情况。

    【讨论】:

    • 感谢您的建议。这非常有效。另一方面,你知道这个实现是否使用队列吗?如果另一个进程锁定了信号量,如何确定允许哪个进程进入临界区的顺序?
    • 没有用于管理这些特定进程的特殊队列。但是,这些新派生的进程被添加到 内核作业调度程序,在那里它们排队(与系统上的所有其他“就绪”进程一起)等待 CPU 时间片。由于调度程序相当复杂并且管理许多任务,它会导致程序中出现竞争条件:选择作业的顺序取决于内核的状态和系统上发生的其他事情,并且该顺序可能会在运行。这就是我在原始帖子中的最后一句话所得到的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-01
    • 1970-01-01
    • 2019-11-26
    • 1970-01-01
    • 2018-05-11
    相关资源
    最近更新 更多