2

我正在使用参考(匿名互斥锁示例)在Linux进行IPCboost::interprocess::shared_memory_object

有一个服务器进程,它创建shared_memory_object并写入它,同时将一个interprocess_mutex包裹在一个scoped_lock;中。和一个客户端进程,它打印另一个人写的任何东西——在这种情况下,它是一个int.

我遇到了一个问题:如果服务器在持有互斥锁时休眠,则客户端进程永远无法获取它并永远等待。

错误的服务器循环:

using namespace boost::interprocess;
int n = 0;
while (1) {
    std::cerr << "acquiring mutex... ";
    {
        // "data" is a struct on the shared mem. and contains a mutex and an int
        scoped_lock<interprocess_mutex> lock(data->mutex);
        data->a = n++;
        std::cerr << n << std::endl;
        sleep(1);
    } // if this bracket is placed before "sleep", everything works
}

服务器输出:

acquiring mutex... 1
acquiring mutex... 2
acquiring mutex... 3
acquiring mutex... 4

客户端循环:

while(1) {
   std::cerr << "acquiring mutex... ";
   {
      scoped_lock<interprocess_mutex> lock(data->mutex);
      std::cerr << data->a << std::endl;
   }
   sleep(1);
}

客户端输出(永远等待):

acquiring mutex...

问题是,如果我将括号移到sleep通话前的那一行,一切正常。为什么?我不认为与锁定的互斥锁一起睡觉会导致互斥锁永远被锁定。

我唯一的理论是,当内核唤醒服务器进程时,作用域结束并释放互斥锁,但等待进程没有机会运行。然后服务器重新获取锁......但这似乎没有多大意义。

谢谢!

4

2 回答 2

7

你的理论是正确的。

如果您查看链接的参考中匿名互斥锁示例的底部,您会看到

正如我们所看到的,互斥锁可用于保护数据,但不能将事件通知给另一个进程。

释放互斥锁不会通知可能正在等待它的其他任何人,并且由于您的进程刚刚醒来,几乎可以肯定它还有足够的调度量来做更多的工作。它将在再次休眠之前循环并重新获取互斥锁,这是客户端必须获取互斥锁本身的第一个机会。

将服务器移出sleep()范围意味着它在互斥锁空闲时进入睡眠状态,让客户端有机会运行并为自己获取互斥锁。

sched_yield()如果您想放弃处理器,但仍然在您的范围内休眠,请尝试调用(仅限 Linux)。sleep(0)也可以工作。

于 2009-06-10T18:24:25.130 回答
0

拿着互斥锁睡觉是错误的。互斥锁保护一些数据(即data->a),并且应该在读/写该数据时最小化范围。

于 2009-06-10T18:22:57.053 回答