锁定boost::unique_lock时抛出的异常,该锁已经锁定在其他线程中
Exception thrown when locking boost::unique_lock which is already locked in other thread
存在全局对象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函数中,我正在做解锁,因为唯一的锁被锁定在构造函数中。延迟确保调度器线程在usb线程之后启动。当它尝试执行lock()时抛出异常。为什么?
您对unique_lock
的使用是错误的,特别是那些不应该在不同线程之间共享的对象,因为它们不是线程安全的。是的,这听起来很奇怪,但它确实有意义,因为线程安全和提供线程安全是两个不同的东西。
unique_lock
的思想是帮助您管理互斥锁上的锁。为此,您只能在本地创建这些对象。这也是它最初被锁定的原因,你似乎可以通过解锁它来"解决"问题。但是,您应该尝试使用它们的作用域/生命周期来管理锁。
现在,你说你需要一个unique_lock
来使用一个事件。是也不是。您需要一个,但不是每个使用该事件的线程都需要一个。相反,您可以使用来自不同线程的不同本地锁实例。顺便说一句:事件需要锁的原因是在等待事件时,锁必须被释放。在接收到事件(或超时)之后,它还必须重新获取锁。换句话说,锁充当互斥锁的代理,提供间接和一些额外的保证。
您收到异常的原因是您尝试锁定unique_lock
两次。我不认为这是来自同一条线索的问题,我甚至不会说它真的来自同一条线索。然而,当你锁定一个互斥锁时(通过unique_lock
),你说你现在进入了一个临界区。这意味着之前,你不在临界区。如果unique_lock
现在发现锁已经持有,这意味着代码中的某些地方出错了,因为代码似乎混淆了它是否在临界区内。因此,您会得到一个异常作为修复代码的动力。
我不熟悉boost同步。从这里的文档中,在我看来,这个想法是创建unique_lock
对象的代码,以便在给定的持续时间(时间,unique_lock
的生命周期等)内拥有mutex
的所有权。我认为你应该尝试锁定mutex
,而不是其他线程中的unique_lock
。
在我看来,unique_lock
对于在方法中锁定mutex
是有用的,并且知道无论发生什么,在方法退出(unique_lock
销毁)时,互斥锁将被释放。您不必确保捕获异常等以便释放mutex
。
消息不是表示您在另一个线程上锁定了互斥锁。这意味着您已经在同一个线程上锁定了互斥锁。由于互斥对象不是递归可锁的,这是一个错误。
你正在手动锁定/解锁互斥锁。
从所示的代码片段中很难看出,但是
很容易- 做错了(忘记及时解锁)
- 几乎不可能使其异常安全(所示代码肯定不是)。
相反,你应该使用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() << "msn"; } 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
仅取决于哪个线程先获取互斥锁
- 如何检查线程是否锁定
- 在两个线程上读/写 64 位,无互斥/锁定/原子
- 如何在实时应用程序中锁定线程
- 锁定来自其他线程的类成员
- 当只有一个线程主要使用该对象而其他线程很少使用它时,如何最小化该对象的互斥锁锁定?
- 将线程锁定很长时间
- C++将互斥锁锁定为来自另一个线程
- 在以读取为主的多线程程序中,可以使用原子来减少锁定吗
- std::weak_ptr<T>::锁定线程安全吗?
- 如何杀死被条件变量锁定的线程?
- 我是否需要在 OpenSSL 1.1.0+ 中使用加密锁定函数来实现线程安全?
- 在任何地方对C++中所有并行线程中的所有锁定和解锁实例使用相同的 std::mutex 和 lock 对象
- 线程锁定互斥锁的速度比 std::conditional_variable::wait() 快
- 线程安全 std::map:锁定整个映射和单个值
- 如何读取锁定多线程C++程序
- 是boost :: lockfree :: Queue(在多线程程序中)可锁定
- C 优化导致线程锁定
- OpenCV 函数在由C++线程程序调用的 Python 脚本本身调用时锁定
- QT 关闭窗口 QTest 在锁定线程中
- 锁定线程安全队列的移动构造函数的右值参数?