【发布时间】:2011-02-14 20:11:56
【问题描述】:
我正在使用 C++ boost::thread 库,这在我的情况下意味着我正在使用 pthreads。正式地,必须从锁定它的同一个线程解锁互斥锁,我想要能够锁定一个线程然后解锁另一个线程的效果。有很多方法可以做到这一点。一种可能性是编写一个允许这种行为的新互斥类。
例如:
class inter_thread_mutex{
bool locked;
boost::mutex mx;
boost::condition_variable cv;
public:
void lock(){
boost::unique_lock<boost::mutex> lck(mx);
while(locked) cv.wait(lck);
locked=true;
}
void unlock(){
{
boost::lock_guard<boost::mutex> lck(mx);
if(!locked) error();
locked=false;
}
cv.notify_one();
}
// bool try_lock(); void error(); etc.
}
我应该指出,上面的代码并不能保证 FIFO 访问,因为如果一个线程调用 lock() 而另一个调用 unlock(),第一个线程可能会先于其他正在等待的线程获取锁。 (想想看, boost::thread 文档似乎没有为互斥锁或条件变量做出任何明确的调度保证)。但现在让我们先忽略它(以及任何其他错误)。
我的问题是,如果我决定走这条路,我是否能够使用这样的互斥锁作为 boost Lockable 概念的模型。例如,如果我使用 boost::unique_lock< inter_thread_mutex > 进行 RAII 样式访问,然后将此锁传递给boost::condition_variable_any.wait() 等,会不会出错?
一方面我不明白为什么不这样做。另一方面,“我不明白为什么不”通常是一种非常糟糕的方式来确定某事是否可行。
我问的原因是,如果事实证明我必须为 RAII 锁和条件变量以及其他任何东西编写包装类,那么我宁愿找到其他方法来实现相同的效果。
编辑: 我想要的那种行为基本上如下。我有一个对象,每当修改它时都需要锁定它。我想从一个线程锁定对象,并对其进行一些工作。然后我想在告诉另一个工作线程完成工作时保持对象锁定。因此,当工作线程完成时,第一个线程可以继续执行其他操作。当工作线程完成后,它会解锁互斥锁。
而且我希望过渡是无缝的,这样在线程 1 开始工作和线程 2 完成工作之间,没有其他人可以得到互斥锁。
inter_thread_mutex 之类的东西似乎可以工作,并且它还允许程序与其交互,就好像它是一个普通的互斥锁一样。所以这似乎是一个干净的解决方案。如果有更好的解决方案,我也很乐意听到。
再次编辑: 我需要锁的原因是有多个主线程,锁在那里防止它们以无效的方式同时访问共享对象。 所以代码已经在主线程级别使用了循环级别的无锁操作序列。此外,在最初的实现中,没有工作线程,互斥锁是普通的 Kosher 互斥锁。
inter_thread_thingy 是作为优化提出的,主要是为了提高响应时间。在许多情况下,保证操作 A 的“第一部分”发生在操作 B 的“第一部分”之前就足够了。举个愚蠢的例子,假设我打对象 1 并给它一个黑眼圈。然后我告诉对象 1 改变它的内部结构以反映所有的组织损伤。在继续打对象 2 之前,我不想等待组织损伤。但是,我确实希望组织损伤作为同一操作的一部分发生;例如,在此期间,我不希望任何其他线程以使组织损坏无效操作的方式重新配置对象。 (是的,这个例子在很多方面都不完美,不,我不是在做游戏)
所以我们对模型进行了更改,其中可以将对象的所有权传递给工作线程以完成操作,它实际上工作得很好;每个主线程都能够完成更多操作,因为它不需要等待它们全部完成。而且,由于主线程级别的事件排序仍然是基于循环的,因此编写高级主线程操作很容易,因为它们可以基于操作完成的假设(更准确地说,关键的“当相应的函数调用返回时,排序逻辑所依赖的第一部分完成)。
最后,我认为使用带有增强锁的 RAII 使用 inter_thread mutex/semaphore thingies 来封装使整个事情正常工作所需的必要同步会很好。
【问题讨论】:
-
Y我们的代码将不起作用,您仍在锁定从不同线程解锁 mx,这将导致未定义的行为。但是信号量会做你想做的事,查一下。
-
其实我认为代码可以工作。 boost 锁是作用域的,这意味着它们在销毁时释放互斥锁。所以 boost::mutex 由锁定它的同一个线程释放。内部互斥锁的目的只是锁定对锁定布尔值的访问。但是,我确实同意我需要的是信号量。实际上,这个 inter_thread_mutex 实际上更像是一个二进制信号量,我称之为互斥量。
-
这段代码看起来很像这段代码picturel.com/ucr/node32.html,用于使用互斥锁实现信号量,该互斥锁从这个精彩的 SO 答案stackoverflow.com/questions/62814/… 链接到关于信号量与互斥锁的关系。 OP 的问题本质上是,
unique_lock等是否适用于信号量以及互斥体。
标签: c++ mutex boost-thread