C++ 使用boost::lock\u-guard时线程不足

C++ 使用boost::lock\u-guard时线程不足,c++,multithreading,boost,C++,Multithreading,Boost,我正在尝试学习boost库,并且正在学习boost::thread的示例 下面的示例说明了如何使用boost::lock_guard进行线程同步,以确保对std::cout的访问不是并发的: #include <boost/thread.hpp> #include <boost/format.hpp> #include <iostream> void wait(const int secs) { boost::this_thread::sleep(b

我正在尝试学习boost库,并且正在学习boost::thread的示例

下面的示例说明了如何使用boost::lock_guard进行线程同步,以确保对std::cout的访问不是并发的:

#include <boost/thread.hpp>
#include <boost/format.hpp>
#include <iostream>

void wait(const int secs) {
    boost::this_thread::sleep(boost::posix_time::seconds(secs));
}

boost::mutex mutex;

void thread1() {
    for (int i = 0; i < 10; ++i) {
        wait(1); // <-- all works fine if wait is placed here
        boost::lock_guard<boost::mutex> lock(mutex);
        std::cout << boost::format("thread A here %d\n") % i ;
    }
}

void thread2() {
    for (int i = 0; i < 10; ++i) {
        wait(1); //  <-- all works fine if wait is placed here
        boost::lock_guard<boost::mutex> lock(mutex);
        std::cout << boost::format("thread B here %d\n") % i;
    }

}

int main() {
    boost::thread t1(thread1);
    boost::thread t2(thread2);
    t1.join();
    t2.join();
}
然而,一个小的修改——将等待调用移动到锁防护的范围内——导致了一个意外:

void thread1() {
    for (int i = 0; i < 10; ++i) {
        boost::lock_guard<boost::mutex> lock(mutex);
        wait(1); // <== !
        std::cout << boost::format("thread A here %d\n") % i ;
    }
}

void thread2() {
    for (int i = 0; i < 10; ++i) {
        boost::lock_guard<boost::mutex> lock(mutex);
        wait(1);  // <== !
        std::cout << boost::format("thread B here %d\n") % i;
    }

谁能解释一下为什么会这样

这是因为在获得锁之后,等待调用会导致第二个线程开始执行。由于第二个线程无法获取锁,因此它将进入等待状态,直到锁可用。在您的情况下,在第一个线程完成其循环之前,锁不可用。

这是正常的。无法保证适配性,尤其是当线程在不到一纳秒的时间内没有锁时。另一个线程根本没有机会获得锁。您的第一个结果也是一个随机结果。典型的互斥体实现不能保证不会饿死,因此您的结果与任何结果一样有效。在您的第一个代码中,您很有可能以锁步方式运行线程,在您的后一种方法中,线程将在解锁互斥锁后立即尝试重新获取互斥锁。@否:我无法想象在这个示例中如何阻止线程运行锁步。您的典型实现没有防范的措辞表明这实际上是可能的。你手头上有论文甚至是实现吗?@Daemon你指的是这两种方法中的哪一种?在第一段代码中,实际上根本没有任何争用,wait调用使线程交替。在2。例如,如果互斥体实现对互斥体上阻塞的任务使用fifo队列,则线程也会交替,而互斥体上阻塞的任务不在OP平台上,而OP平台在unix上非常典型implementations@nos:我指的是第二段。我很难想象一个非典型的互斥锁怎么能避免线程运行lockstep,因为它是在线程进入睡眠状态时保持的。它必须类似于Windows完成端口的工作方式,如果其中一个活动线程阻塞I/O,它会唤醒另一个阻塞的线程。但是这种事情对于互斥锁来说是无效的。即使线程没有执行,它仍然在互斥程序段内,同时保持互斥。否则,重新调度也意味着释放互斥锁。
void thread1() {
    for (int i = 0; i < 10; ++i) {
        boost::lock_guard<boost::mutex> lock(mutex);
        wait(1); // <== !
        std::cout << boost::format("thread A here %d\n") % i ;
    }
}

void thread2() {
    for (int i = 0; i < 10; ++i) {
        boost::lock_guard<boost::mutex> lock(mutex);
        wait(1);  // <== !
        std::cout << boost::format("thread B here %d\n") % i;
    }
thread B here 0
thread B here 1
thread B here 2
thread B here 3
thread B here 4
thread B here 5
thread B here 6
thread B here 7
thread B here 8
thread B here 9
thread A here 0
thread A here 1
thread A here 2
thread A here 3
thread A here 4
thread A here 5
thread A here 6
thread A here 7
thread A here 8
thread A here 9