1

有没有办法在等待互斥锁锁定时执行代码部分?

对我的应用程序性能唯一真正的内部影响是数据库交互,有时我需要严格同步,因为数据库交互可能会导致争用,所以我想利用等待锁的时间从数据库。

例如,我希望代码看起来像伪代码:

boost::unique_lock<boost::mutex> process_lock(process_mutex, work_while_contending);
//code to execute while lock contending
process_lock.proceed_after_lock();

我检查了 boost 的同步部分,虽然futuresrecursive听起来我的意图可以实现,但我不知道如何实现我的意图。

我的意图如何实现?

4

2 回答 2

3

在大多数情况下,您真的不想这样做。如果您确实想这样做,您可能想要使用期货,如下所示:

auto f = std::async(std::launch::async, [&]() {
   // do work in another thread here.
});

boost::unique_lock<boost::mutex> process_lock(process_mutex);
auto result = f.get();

// proceed here the work is done and you have the lock

...这使您可以在原始线程等待互斥锁时在另一个线程中工作。一旦这两项工作都完成并获得了互斥锁,线程就会继续。如果工作在获得互斥体之前完成,那么工作线程将消失,原始线程将只是空闲等待互斥体。

这就是您不想这样做的原因:如果您在工作完成之前获取互斥锁,那么其他线程将无法获取互斥锁,程序将在等待“后台”工作完成时停止。

一种可能的解决方案是使用带有非阻塞的繁忙等待循环try_lock。这里的潜在问题是线程没有等待互斥体,因此不能保证线程会得到它。如果它有很多争用,而其他人正在积极等待,那么你永远不会得到它。如果您等待它,那么通常操作系统会保证某种顺序,以便您最终得到它。如果您不等待,则无法做出该保证。

于 2014-05-28T00:56:02.683 回答
2

这实际上很容易。您可以调用不同的构造函数来请求延迟互斥锁上的实际锁。然后可以调用 try_lock() 方法来尝试获取锁,这是一个非阻塞调用,返回一个布尔值,指示是否成功获取了锁。在您的情况下,您可以像这样使用此方法:

boost::unique_lock<boost::mutex> process_lock(process_mutex, boost::defer_lock_t);
while(!process_lock.try_lock())
{
    ...do some work
}

一旦锁成功获得互斥锁,它将像往常一样负责再次解锁它,因此您没有引入任何异常处理问题。

编辑:刚刚对这个问题有了另一个想法。如果每次锁定尝试失败时您都想运行一项任务,我给出的答案非常好,但是如果您想做的工作只需要在第一次尝试时无法获得锁定的情况下完成一次,则以下方法会更合适:

boost::unique_lock<boost::mutex> process_lock(process_mutex, boost::try_to_lock_t);
if(!process_lock.owns_lock())
{
    ...do some work
    process_lock.lock();
}
于 2014-05-28T00:43:11.590 回答