Boost w/ C++ - 奇怪的互斥行为

Boost w/ C++ - Curious mutex behavior

我正在试验 Boost 线程,据我所知,我可以编写多线程 Boost 应用程序并在 Windows 或 Linux 中编译它,而我更熟悉的 pthreads 严格用于 *NIX 系统。

我有以下示例应用程序,which is borrowed from another SO question


#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>

#define NAP_DURATION    (10000UL)   // 10ms

boost::mutex io_mutex;

void count(int id)
{
    for (int i = 0; i < 1000; ++i)
    {
        boost::mutex::scoped_lock lock(io_mutex);
        std::cout << "Thread ID:" << id << ": " << i << std::endl;
        if (id == 1)
        {
            std::cout << "I'm thread " << id << " and I'm taking a short nap" << std::endl;
            usleep(NAP_DURATION);
        }
        else
        {
            std::cout << "I'm thread " << id << ", I drink 100 cups of coffee and don't need a nap" << std::endl;
        }
        std::cout << "Thread ID:" << id << ": " << i << std::endl;
        boost::thread::yield();
    }
}

int main(int argc, char* argv[])
{
    boost::thread thrd1( boost::bind(&count, 1));
    boost::thread thrd2( boost::bind(&count, 2));

    thrd1.join();
    thrd2.join();
    return 0;
}

我通过以下方式在我的 Ubuntu 14.04 LTS 系统上安装了 Boost:

sudo apt-get install libboost-all-dev

我通过以下方式编译上面的代码:

g++ test.cpp -lboost_system -lboost_thread -I"$BOOST_INLCUDE" -L"$BOOST_LIB"

我 运行 发现了一些有趣的矛盾之处。如果我设置一个很长的 NAP_DURATION,比如 1 秒 (1000000),似乎只有线程 1 在完成其操作之前获得互斥量,并且线程 [=19] 很少见=] 在线程 1 完成之前获得锁,即使我将 NAP_DURATION 设置为几毫秒也是如此。

当我使用 pthreads 编写类似的此类应用程序时,锁通常会或多或少地在线程之间随机交替,因为另一个线程已经被互斥体阻塞。


所以,对于问题:

  1. 这是预期的行为吗?
  2. 有没有办法控制这种行为,例如让作用域锁的行为就像锁定操作排队一样?
  3. 如果 (2) 的答案是“否”,是否可以使用 Boost 条件变量实现类似的功能而不必担心 lock/unlock 调用失败?
  4. 是否保证 scoped_lock 解锁?我正在使用 RAII 方法而不是手动 locking/unlocking 因为显然解锁操作可能会失败并引发异常,我正在努力使这段代码可靠。

谢谢。

澄清

我知道将调用线程置于睡眠状态不会解锁互斥量,因为它仍在范围内,但预期的调度是这样的:

你到底为什么感到惊讶? 如果您期望线程 2 在线程 1 休眠时获取互斥量,那么,是的,这是预期的行为,您的理解是错误的,因为您的锁在范围内。

但是如果你因为在循环迭代结束时线程 1 和线程 2 之间缺乏交替而感到惊讶,那么你可以看看 this SO question 关于调度似乎 "unfair"

Is this expected behavior?

是也不是。您不应该对哪个线程将获得互斥锁有任何期望,因为它是未指定的。但它肯定在预期行为的范围内。

Is there a way to control this behavior, such as making scoped locks behave like locking operations are queued?

不要以这种方式使用互斥锁。只是不要。只使用互斥体,这样它们相对于线程正在做的其他事情来说会保持很短的时间。

If the answer to (2) is "no", is it possible to achieve something similar with Boost condition variables and not having to worry about lock/unlock calls failing?

当然可以。编码你想要的。

Are scoped_locks guaranteed to unlock? I'm using the RAII approach rather than manually locking/unlocking because apparently the unlock operation can fail and throw an exception, and I'm trying to make this code solid.

不清楚您担心的是什么,但建议使用 RAII 方法。