有全局对象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()时抛出异常。为什么呢?
答案 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
仅取决于哪个线程首先抓取互斥锁。