锁定已锁定在其他线程中的boost :: unique_lock时抛出异常

时间:2015-06-02 15:43:23

标签: c++ multithreading boost

有全局对象boost :: unique_lock。一个线程锁定它。当其他线程试图锁定异常“已经拥有互斥锁”时抛出。为什么会这样?我希望线程被阻塞,直到其他线程将调用unlock。

boost::mutex mutex;
boost::unique_lock<boost::mutex> lock(mutex);

static void* scheduller(void* arg)
{
    boost::this_thread::sleep(boost::posix_time::seconds(5));
    lock.lock();    
    return 0;
}

static void* usb(void* arg)
{
    lock.lock();
    boost::this_thread::sleep(boost::posix_time::seconds(20));
    return 0;
}

int BEvent_test()
{
    lock.unlock();
    int a = 0;
    boost::thread thread1(usb,&a);
    boost::thread thread2(scheduller,&a);
    boost::this_thread::sleep(boost::posix_time::seconds(100));
    return 0;

}

在BEvent_test函数中我正在解锁,因为在构造函数中锁定了唯一的锁。延迟确保scheduller线程在usb线程之后启动。当它尝试执行lock()时抛出异常。为什么呢?

3 个答案:

答案 0 :(得分:4)

您对unique_lock的使用是错误的,特别是那些的对象应该在不同的线程之间共享,因为它们不是线程安全的。是的,这听起来很奇怪,但它确实有意义,因为线程安全并提供线程安全是两个截然不同的事情。

unique_lock的想法是帮助您管理对互斥锁的锁定。为此,您只能在本地创建这些对象。这也是它最初被锁定的原因,你似乎通过解锁来“解决”它。但是,您应该尝试使用其范围/生命周期来管理锁定。

现在,您说您需要unique_lock才能使用某个活动。是的,不是。对于使用该事件的每个线程,您需要一个但不完全相同的一个。相反,您可以使用来自不同线程的不同本地锁实例。 BTW:事件需要锁定的原因是在等待事件时,必须释放锁定。收到事件(或超时)后,它还必须重新获取锁定。换句话说,锁用作互斥锁的代理,提供间接和一些额外的保证。

您收到异常的原因是您尝试锁定unique_lock两次。我不认为这是来自同一个线程的重要,我甚至不会说它确实是来自同一个线程。但是,当您锁定互斥锁(通过unique_lock)时,表示您现在正在进入关键部分。这意味着之前,你不在那个关键部分。如果unique_lock现在发现锁定已经存在,则意味着代码中的某些内容出错了,因为代码似乎是混淆的,无论它是否在关键部分内。出于这个原因,您将获得异常作为修复代码的动机。

答案 1 :(得分:2)

我不熟悉boost同步。在文档here中,我认为这个想法是创建mutex对象以在给定的持续时间内拥有unique_lock所有权的代码(时间,{的生命周期{1}}等)。我想你应该尝试锁定mutex,而不是其他线程中的unique_lock

我看到它的方式,unique_lock对于锁定方法中的mutex很有用,并且知道无论发生什么,在方法的退出(unique_lock破坏),互斥锁将被释放。您不必确保捕获异常等,以便释放mutex

答案 2 :(得分:2)

消息表示您在另一个线程上锁定了互斥锁。这意味着您已将互斥锁锁定在同一线程上。由于您的互斥锁不是递归可锁定的,因此这是一个错误。

您正在手动锁定/解锁互斥锁。

从所显示的代码片段中很难看到,但它很容易

  • 做错了(忘了及时解锁)
  • 几乎不可能让它异常安全(显示的代码肯定不是)。

相反,您应该使用scoped_lock(或lock_guard / unique_lock)自动平衡锁定/解锁并以异常安全的方式进行平衡。

<强>更新

在重新阅读代码时,您只是使用unique_lock完全错误:

<强> Live On Coliru

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread.hpp>
#include <iostream>

#define TRACE(msg) do { std::cout << msg << " " << __FUNCTION__ << " at " << relative_ms() << "ms\n"; } while(false)

int relative_ms() {
    using boost::posix_time::second_clock;
    static auto t0 = second_clock::local_time();

    return (second_clock::local_time() - t0).total_milliseconds();
}

boost::mutex mutex;

static void scheduler()
{
    boost::unique_lock<boost::mutex> lock(mutex);
    TRACE("Enter");

    boost::this_thread::sleep_for(boost::chrono::seconds(2));

    TRACE("Leave");
}

void usb()
{
    boost::unique_lock<boost::mutex> lock(mutex);
    TRACE("Enter");

    boost::this_thread::sleep_for(boost::chrono::seconds(5));

    TRACE("Leave");
}

int main()
{
    TRACE("Enter");
    boost::thread thread1(usb);
    boost::thread thread2(scheduler);
    boost::this_thread::sleep_for(boost::chrono::seconds(10));
    TRACE("Leave");
}

打印例如。

Enter main at 0ms
Enter usb at 0ms
Leave usb at 5000ms
Enter scheduler at 5000ms
Leave scheduler at 7000ms
Leave main at 10000ms

Enter main at 0ms
Enter scheduler at 0ms
Leave scheduler at 2000ms
Enter usb at 2000ms
Leave usb at 7000ms
Leave main at 10000ms

仅取决于哪个线程首先抓取互斥锁。