信号量不会使进程休眠

Posted

技术标签:

【中文标题】信号量不会使进程休眠【英文标题】:Semaphore won't make the process sleep 【发布时间】:2014-05-12 09:01:19 【问题描述】:

以下代码有问题:

#include "updaterankparams.hpp"

int main()

sem_id = semget(SEM_KEY, 1, 0);

while(true)

    printf("want to lower: %d\n", semctl(sem_id, 0, GETVAL));
    semop(sem_id, &P, 1);
    printf("lowered: %d\n", semctl(sem_id, 0, GETVAL));
    scanf("%*c");
    puts("t");
    semop(sem_id, &V, 1);

return 0;

在哪里

static sembuf P =

  0,
  -1,
  0
;

static sembuf V =

  0,
  1,
  0
;

我得到的输出是:

done
want to lower: 0
lowered: 0

t
want to lower: 1
lowered: 0

t
want to lower: 1
lowered: 0

当我输入字符以满足循环中的 printf 时,它会无限循环。 但是我希望进程在尝试降低值已经为零的信号量时停止(睡眠)。虽然,没有任何事情发生!我知道这可能是一件愚蠢的事情,而且解决方案也很简单,但这是其中一个非常愚蠢的错误,我想甚至没有人在网上要求解决方案。

只是为了澄清:没有其他进程使用信号量,并且它已在其他(现已关闭)进程中使用:

sem_id = semget(SEM_KEY, 1, 0666 | IPC_CREAT);

感谢大家的帮助!

【问题讨论】:

能否请您发布足够的代码,以便我们运行它并观察您的问题? 您在循环中执行 P 和 V,P 始终为值 1。它应该在哪里停止,为什么? 如果你想运行它,只需将带有 semget 的行添加到代码中并用一些整数定义 SEM_KEY,例如2000000001 【参考方案1】:

TL;DR:你必须用semget创建信号量,然后用semop给它一个“值”,默认是0(整洁:))。

据我所知,您的 P 和 V sembufs 分别被 1 个资源锁定和解锁。

编辑:您的信号量在开始时的值为 0,因为您尚未对其进行初始化。看看例子given here即:

/* Semaphore does not exist - Create. */
if ((semid = semget(semkey, 1, IPC_CREAT | IPC_EXCL | S_IRUSR |
    S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) != -1)

    /* Initialize the semaphore. <- v THIS IS IMPORTANT v */
    sbuf.sem_num = 0;
    sbuf.sem_op = 2;  /* This is the number of runs
                         without queuing. <- THIS IS WHERE YOU SET IT TO 1 */
    sbuf.sem_flg = 0;
    if (semop(semid, &sbuf, 1) == -1) 
        perror("IPC error: semop"); exit(1);
    

我认为你在同一个信号量中混合了信号量的数量和可用资源的数量,我做到了。 semget 创建 1 个信号量,但您必须将其设置为 1 个可用资源,并调用 semop。一个信号量可以与多个可用资源一起使用(参见下面的训练示例)。

在您的while 循环中,您首先锁定信号量,使用semop(sem_id, &amp;P, 1); 行,然后您解锁它立即使用semop(sem_id, &amp;V, 1); 行。 p>

这在您的main 中,我猜您没有其他线程正在运行,因此无法同时访问您的资源和信号量。您的程序将永远不必等待,因为信号量被锁定,您输入一个字符,信号量被解锁然后在下一个循环通过时再次锁定。当您尝试锁定信号量时,信号量的值永远不会为 0,因为它之前已被释放。

如果您想试用信号量并获得等待时间,请查看线程。一个很好的练习是尝试让 3 辆火车只穿过 1 座桥,并有一个像这样的小展示,例如:

[][][][]>--------________---------
[][][][]>--------        ---------
[][][][]>--------        ---------

你的资源限制是桥(这里只有一个),每列火车有一个线程,做同样的事情,比如:

//Init the semaphore with 1 ressource available (the one bridge)
semop(sem_id, &V, 1);

//Threaded code :
while (position != trackSize)

  if ((position < (bridgePosition - 1))  //Before the bridge
      || (position > bridgeEnd))   //After the bridge
  
    position++;
  
  else //On the bridge
  
    if (semop(sem_id, &P, 1) != -1) //Lock the bridge for this train
                                    // will wait if the bridge is already in use
    
      while (position < bridgeEnd) position++; //Go through the bridge at once
    
    semop(sem_id, &V, 1); //Unlock the bridge, let other trains use it
  

如果您有 2 个网桥,您仍然有 1 个信号量/sem_id,但您会将其设置为 2 个可用资源,因此两列火车可以同时“锁定”同一个信号量。

我希望这可以帮助您理解为什么您在程序执行过程中没有等待。

【讨论】:

我意识到程序应该运行而无需等待,因为锁定和解锁几乎同时发生,但困扰我的是我在锁定信号量之前打印信号量的值和第一个程序锁定这个值的时间是0,但每次都是1。那么,如果信号量值在锁定之前为0(第一次使用信号量),程序怎么能锁定它并继续进行? 从你的输出中,我看到want to lower: 1,所以不知道你在锁定之前在哪里看到的值为0?编辑:啊,你的意思只是第一次,对不起 done 输出从何而来?在semget 和第一个循环之间,您还有其他代码在运行吗? 对不起,我的错。在发布代码之前,我尝试尽可能地简化代码,因此我删除了循环之前完成的行打印。抱歉造成混乱,但没有此打印的重新编译会产生相同的效果(当然,除了打印完成 :)) 您认为这可能是输出流问题(例如,在程序运行的其他时刻正在读取信号量的值)吗?因为它似乎工作正常,只是输出困扰着我......

以上是关于信号量不会使进程休眠的主要内容,如果未能解决你的问题,请参考以下文章

如何使用信号调用同一进程中的另一个线程在轮询函数上休眠的进程而不杀死它?

linux驱动程序中的并发控制-5(信号量(semaphore))-47

linux驱动程序中的并发控制-5(信号量(semaphore))-47

linux驱动程序中的并发控制-5(信号量(semaphore))-47

如何使用信号量使子进程相互同步?

linux 内核睡眠与唤醒