【发布时间】:2014-08-21 14:13:36
【问题描述】:
我有一些函数试图锁定std::mutex,如果互斥锁成功锁定,函数会创建std::thread,使用lambda-function 作为线程函数参数,并使用std::move() 传递锁定:
static std::mutex mtx;
// some mutex defended stuff
void someFunc() {
// try lock mutex using unique_lock
std::unique_lock<std::mutex> lock(mtx, std::try_to_lock);
if(!lock.owns_lock()) {
return; // locking fails
}
// task for thread
auto task = [&](std::unique_lock<std::mutex>&& lock) {
// do async work and release lock when it done
lock.unlock();
// do something after releasing lock
};
// create thread, pass lock
std::thread taskThread(task, std::move(lock));
taskThread.detach();
}
我遇到编译器错误:
<lambda_1918cc58d906c210588b1a8bb33f1b0d>::operator
()(std::unique_lock<_Mutex> &&) const' : cannot convert parameter 1 from
'std::unique_lock<_Mutex>' to 'std::unique_lock<_Mutex> &&'
我应该如何正确地将std::unique_lock 传递给我的 lambda?
统一更新: 实际上这个函数是一个原生的 C API libaray 调用,它尝试异步启动一些库操作并在任何情况下立即返回控制,返回一些返回码给调用者。此代码已简化以专注于特定问题。
【问题讨论】:
-
你想用这个实现什么?您可能不应该将
lock传递到线程中。它已经可以访问“mtx”,这正是它所需要的。 -
始终保持锁定真的很重要吗?我的意思是,如果等待结果的人不认为启动异步任务及其执行的步骤是原子的,您是否会冒数据损坏的风险?在我看来,您可能想要这样做,因为您使用互斥锁的锁定状态来监视异步执行的状态,这是一种反模式。
-
@Christophe 如果他这样做了,那么
somefunc()中的 lambda 和unique_lock都会unlock()互斥体,这是未定义的行为。 -
嗯,我刚刚意识到你的代码即使编译也有未定义的行为。您正在从不同的线程锁定和解锁
mutex,这是不允许的。解锁它的线程必须与锁定它的线程相同。无论如何,由于this bug,您的代码无法在 VC12 上编译
标签: c++ multithreading c++11 concurrency lambda