我正在使用 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()
, etc.
一方面我不明白为什么不。另一方面,“我不明白为什么不”通常是确定某件事是否有效的非常糟糕的方式。
我问的原因是,如果事实证明我必须为 RAII 锁和条件变量以及其他任何内容编写包装类,那么我宁愿寻找其他方法来实现相同的效果。
编辑:
我想要的行为基本上如下。我有一个对象,每当修改它时都需要锁定它。我想从一个线程锁定该对象,并对其进行一些工作。然后我想在告诉另一个工作线程完成工作时保持对象锁定。因此,当工作线程完成时,第一个线程可以继续执行其他操作。当工作线程完成时,它会解锁互斥体。
我希望过渡是无缝的,这样当线程 1 开始工作和线程 2 完成工作之间没有其他人可以获得互斥锁。
像 inter_thread_mutex 这样的东西似乎可以工作,并且它还允许程序与它交互,就像它是一个普通的互斥体一样。所以这似乎是一个干净的解决方案。如果有更好的解决方案,我也很高兴听到。
再次编辑:
我首先需要锁的原因是有多个主线程,锁的作用是防止它们以无效的方式同时访问共享对象。
因此,代码已经在主线程级别使用了循环级无锁操作序列。此外,在最初的实现中,没有工作线程,并且互斥体是普通的犹太互斥体。
inter_thread_thingy 是作为一种优化而出现的,主要是为了提高响应时间。在许多情况下,足以保证操作 A 的“第一部分”发生在操作 B 的“第一部分”之前。举一个愚蠢的例子,假设我打了对象 1 并给它打了一个黑眼圈。然后我告诉对象 1 改变它的内部结构以反映所有的组织损伤。我不想在继续打孔对象 2 之前等待组织损伤。但是,我确实希望组织损伤作为同一操作的一部分发生;例如,在此期间,我不希望任何其他线程以会使组织损坏成为无效操作的方式重新配置对象。 (是的,这个例子在很多方面都不完美,而且我不是在开发游戏)
因此,我们对模型进行了更改,其中可以将对象的所有权传递给工作线程以完成操作,并且它实际上工作得很好;每个主线程都能够完成更多的操作,因为它不需要等待所有操作完成。而且,由于主线程级别的事件排序仍然基于循环,因此很容易编写高级主线程操作,因为它们可以基于操作已完成的假设(更准确地说,关键的“当相应的函数调用返回时,排序逻辑所依赖的第一部分已完成)。
最后,我认为使用带有 boost 锁的 RAII 的线程间互斥/信号量事物来封装使整个事情正常工作所需的必要同步会很好。