c++ 关于LevelDB的`PosixEnv::Schedule`的实现,我有一个问题:为什么`Schedule`在插入新任务到队列之前调用`Signal`?

ny6fqffe  于 2023-04-01  发布在  LevelDB
关注(0)|答案(1)|浏览(238)

我正在尝试阅读LevelDB源代码。下面的一些代码:

void PosixEnv::Schedule( void (*background_work_function)(void* background_work_arg), void* background_work_arg) {
  background_work_mutex_.Lock();

  // Start the background thread, if we haven't done so already.
  if (!started_background_thread_) {
    started_background_thread_ = true;
    std::thread background_thread(PosixEnv::BackgroundThreadEntryPoint, this);  
    background_thread.detach();
  }

  // If the queue is empty, the background thread may be waiting for work.
  if (background_work_queue_.empty()) {
    background_work_cv_.Signal();
  }

  background_work_queue_.emplace(background_work_function, background_work_arg);
  background_work_mutex_.Unlock();
}

void PosixEnv::BackgroundThreadMain() {
  while (true) {
    background_work_mutex_.Lock();

    // Wait until there is work to be done.
    while (background_work_queue_.empty()) {
      background_work_cv_.Wait();
    }

    assert(!background_work_queue_.empty());
    auto background_work_function = background_work_queue_.front().function;
    void* background_work_arg = background_work_queue_.front().arg;
    background_work_queue_.pop();

    background_work_mutex_.Unlock();
    background_work_function(background_work_arg);
  }
}

关于Schedule,我想知道为什么在将新任务推入队列之前**当find queue为空时调用background_work_cv_.Signal()
在我看来,Schedule可以写如下来做同样的事情:

void PosixEnv::Schedule( void (*background_work_function)(void* background_work_arg), void* background_work_arg) {
  background_work_mutex_.Lock();

  ...

  background_work_queue_.emplace(background_work_function, background_work_arg);
  background_work_mutex_.Unlock();
  background_work_cv_.Signal(); // cv.notify_one();
}

我想知道这两者有什么不同吗?为什么一定要第一次实施?第二次实施是否在某些方面有缺陷,没有考虑到某种情况?

3hvapo4f

3hvapo4f1#

是的,如果没有线程等待,调用信号没有什么坏处,所以你的实现会很好。很难说为什么要这样实现。也许开发人员担心对信号的冗余调用会减慢代码的速度?如果是这样的话,这样的事情应该被衡量(也许他们真的测量过?)基本上,只有当你知道有人在等你的时候,调用signal才是合乎逻辑的,所以很难责怪开发人员。这可能只是他们想到的第一件事。
还要注意的是,在这段代码中,无论你是在将某个东西推入队列之前还是之后调用signal都没有关系,锁仍然被占用,所以在锁被释放之前,其他线程无法检查队列的状态。

相关问题