linux - IPC 命名信号量的 POSIX 实现

标签 linux posix ipc semaphore

我正在做一项家庭作业,涉及实现信号量以强制子进程之间的互斥。我的大部分代码都在工作,只是我没有正确使用信号量。我找到的文章没有多大帮助。有人可以向我解释 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);
        }
    }

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

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

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

最佳答案

尝试将 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);
}

我不认为您对不遵守关键段的进程有任何问题(尽管信号量是一种荣誉系统,就像常规的 parking 灯一样......)。我认为问题在于进程 B 正在等待进程 A 持有的锁,当 A 售出最后一张票时并释放锁,B 捕获锁并出售另一张票,因为它已经检查过票是否可用并且在出售最后一张之前不再检查。

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

关于linux - IPC 命名信号量的 POSIX 实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59023896/

相关文章:

linux - 电子表格。数据包类型 "otherhost"

c++ - 如何在 Mac OS X 中获取 aio 信号处理程序的用户数据

c - 如何确定每次读取系统调用要读取的合理字节数?

c++ - IPC 与 QSharedMemory 和风险,如果其中一个进程挂起

c - filp_open 在字符设备驱动程序的释放函数中崩溃

linux - 获取不同 HPUX unix 服务器的 CPU 和内存信息

java - 如何在 Linux Mint 中为 Intellij 创建菜单项?

c - 用 SIGTERM 杀死 child

c++ - Linux下如何检测另一个进程并与其通信?

perl - 从 perl 调用和控制 GDB