【问题标题】:Boost mutex locking on same thread在同一线程上增强互斥锁
【发布时间】:2012-11-28 04:11:45
【问题描述】:

我是 boost 库的新手,它真是一个了不起的库!另外,我是互斥锁的新手,如果我犯了新手错误,请原谅我。

不管怎样,我有两个函数叫做FunctionOneFunctionTwoFunctionOneFunctionTwo 由不同的线程异步调用。所以这就是发生的事情:在FunctionOne 中,我在函数开头锁定了一个全局互斥锁,并在函数末尾解锁了全局互斥锁。 FunctionTwo 也一样。

现在问题来了:有时,FunctionOneFunctionTwo 的调用间隔不到几毫秒(但并非总是如此)。因此,FunctionOne 开始执行,FunctionTwo 执行到一半。当FunctionTwo 锁定互斥体时,FunctionOneFunctionTwo 所在的整个线程都将停止,因此FunctionOne 被卡在中途,线程在FunctionTwo 中永远等待自己。所以,总结一下:

  • 函数 1 锁定互斥体并开始执行代码。
  • 函数 2 在几毫秒后被调用并锁定互斥锁,冻结线程 func 1 和 2 处于打开状态。
  • 现在 func 1 中途卡住了,线程被冻结,所以 func 1 永远不会完成,互斥锁被永远锁定,等待 func 1 完成。

在这种情况下,人们会怎么做?这是我的代码:

boost::mutex g_Mutex;
lua_State* L;

// Function 1 is called from some other thread
void FunctionOne()
{
    g_Mutex.lock();

    lua_performcalc(L);

    g_Mutex.unlock();
}

// Function 2 is called from some other thread a few ms later, freezing the thread
// and Function 1 never finishes
void FunctionTwo()
{
    g_Mutex.lock();

    lua_performothercalc(L);

    g_Mutex.unlock();
}

【问题讨论】:

  • 如果 f1 和 f2 被同一个线程调用,那么在 f1 仍在进行中时如何调用 f2?你的意思是从 f1 调用 f2 吗?
  • 这就是我感到困惑的地方。我确定 FunctionOne 和 FunctionTwo 是从单独的线程调用的。但是,我做了以下事情:printf("Function: %s, time: %f", __FUNCTION__, globals->currentTime()); 有时会同时调用这两个函数(并且应用程序因写入同一资源而崩溃),并且使用互斥锁,应用程序会在自己的线程上等待。
  • -1 该问题需要 SSCCE。请参阅sscce.org 就像您在浪费自己的时间一样,也是在浪费我们的时间。 更新嗯。为什么 RSS 提要中有旧问题?
  • 我很好奇,你有没有深入了解这个问题?看来您对问题的描述首先违反了“互斥体”的原则......

标签: c++ boost lua mutex


【解决方案1】:

这些函数是否旨在可重入,以便 FunctionOne 在持有互斥锁的同时调用自身或 FunctionTwo?反之亦然,FunctionTwo 锁定互斥体,然后在互斥体锁定时调用 FunctionOne/FunctionTwo?

  • 如果不是,那么您不应该从同一个线程调用这两个函数。如果您打算在 FunctionOne 完成之前阻塞 FunctionTwo,那么在同一个线程上调用它是错误的。如果 lua_performcalc 最终调用 FunctionTwo,就会发生这种情况。这是在同一线程上调用它们的唯一方法。

  • 如果是这样,那么您需要一个recursive_mutex。一个普通的互斥锁只能被锁定一次;从同一个线程再次锁定它是一个错误。一个递归互斥锁可以被单个线程多次锁定,并一直锁定到线程调用 unlock 相同次数为止。

在任何一种情况下,您都应该避免显式调用 lock 和 unlock。如果抛出异常,互斥锁将不会被解锁。最好使用 RAII 样式的锁定,如下所示:

{
    boost::recursive_mutex::scoped_lock lock(mutex);

    ...critical section code...

    // mutex is unlocked when 'lock' goes out of scope
}

【讨论】:

  • 即使需要重入调用,也可以避免递归互斥。
  • 这两个函数保证永远不会相互调用或调用自身,但两个函数使用相同的资源和子程序(例如 lua_getglobal、lua_gettop 等)。当我记录 FunctionOne 和 FunctionTwo 的运行时间时,它们被不同的线程同时调用(到小数点后 8 位),其中线程永远挂起。有时函数调用相隔几毫秒,然后就没有问题(通常,除非时间差很小)。我不认为两个函数可以在同一个线程上同时执行,所以我不知道为什么会这样。
【解决方案2】:

您的描述不正确。互斥锁不能被锁定两次。你有不同的问题。

  • 在互斥锁被锁定时检查重入。
  • 检查异常

为避免出现异常问题,您应该使用boost::mutex::scoped_lock (RAAI)

【讨论】:

  • 有了 scoped_lock,等待问题就解决了,但现在这两个函数似乎同时写入同一个资源。显然有些东西我不明白。 :(
  • 如果 scoped_lock 确实解决了死锁,那么 'lua_performcalc(L);'可能是在扔。
  • 当我记录时间时,有时 FunctionOne 和 FunctionTwo 会同时触发(精确到小数点后 8 位),并且 lua_performcalc 和 lua_performothercalc 尝试写入相同的资源并崩溃。有时当它们相隔几毫秒时,它们也会崩溃。只有当这两个函数相隔几百毫秒时,它们才不会崩溃。当我改用g_Mutex.lock() 时,线程会自行挂起。我以为两个函数不能在同一个线程上同时执行,所以我不知道为什么会这样。
  • 刚刚发现线程也因作用域锁而冻结... :(
  • 这是新闻。您没有发布必要的代码。现在的猜测是:函数之外的某个人正在操作 L 指向的数据,或者 calc 函数使用了外部损坏的其他全局数据
猜你喜欢
  • 2013-05-28
  • 1970-01-01
  • 2014-05-02
  • 1970-01-01
  • 1970-01-01
  • 2013-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多