1

假设我编写了一个 C++ 信号量类,其接口模拟了 boost Lockable 概念(即lock(); unlock(); try_lock();等)。对此类对象的 RAII 访问使用增强锁是否安全/推荐?换句话说,boost 锁(和/或 boost 线程库的其他相关部分)是否假设 Lockable 概念只能由从同一线程锁定和解锁的类似互斥体的对象建模?

我的猜测是使用信号量作为 Lockable 的模型应该没问题。我浏览了一些增强源,它“似乎”还可以。这些锁似乎没有存储对 this_thread 或类似内容的显式引用。此外,Lockable 概念没有像whichThreadOwnsMe(). 看起来我什至应该能够传递boost::unique_lock<MySemaphore>boost::condition_variable_any::wait. 但是,文档并没有明确说明这些要求。

为了说明我的意思,考虑一个简单的二进制信号量类:

class MySemaphore{
  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.
}

现在假设某个地方,无论是在对象上还是在全局范围内,我都有

MySemaphore sem;

我想使用 RAII 锁定和解锁它。此外,我希望能够将锁的所有权从一个线程“传递”到另一个线程。例如,在一个线程中我执行

void doTask()
{
  boost::unique_lock<MySemaphore> lock(sem);
  doSomeWorkWithSharedObject();
  signalToSecondThread();
  waitForSignalAck();
  lock.release();
}

当另一个线程正在执行类似

{
waitForSignalFromFirstThread();
ackSignal();
boost::unique_lock<MySemaphore>(sem,boost::adopt_lock_t());
doMoreWorkWithSameSharedObject();
}

我这样做的原因是我不希望其他人能够在第一个线程执行的时间和第二个线程执行的时间sem之间获得锁定。基本上,我将一项任务分为两部分。我将任务拆分的原因是(1)我希望任务的第一部分尽快开始,(2)我想保证第一部分在 doTask() 返回之前完成, (3) 我希望任务的第二个更耗时的部分由另一个线程完成,可能是从等待完成由主线程启动的任务的从属线程池中选择的。doSomeWorkWithSharedObject()doMoreWorkWithSameSharedObject()

注意:我最近在这里发布了同样的问题(有点)Modeling boost::Lockable with semaphore 而不是 mutex (以前的标题:Unlocking a mutex from a different thread) 但我将互斥锁与信号量混淆了,所以关于使用升压锁的问题并没有真正得到解决。

4

1 回答 1

2

@dan,我认为你把事情复杂化了。您所描述的内容很容易通过主处理线程、同步队列和 [pool of] 工作线程来实现。看起来您也陷入了使用锁来“保护代码”的常见陷阱,而您需要保护的是数据结构。

定义您的共享数据,在数据可能不一致时确定最小的关键部分。用锁支撑它。

于 2010-05-03T01:50:56.307 回答