我正在尝试阅读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();
}
我想知道这两者有什么不同吗?为什么一定要第一次实施?第二次实施是否在某些方面有缺陷,没有考虑到某种情况?
1条答案
按热度按时间3hvapo4f1#
是的,如果没有线程等待,调用信号没有什么坏处,所以你的实现会很好。很难说为什么要这样实现。也许开发人员担心对信号的冗余调用会减慢代码的速度?如果是这样的话,这样的事情应该被衡量(也许他们真的测量过?)基本上,只有当你知道有人在等你的时候,调用signal才是合乎逻辑的,所以很难责怪开发人员。这可能只是他们想到的第一件事。
还要注意的是,在这段代码中,无论你是在将某个东西推入队列之前还是之后调用signal都没有关系,锁仍然被占用,所以在锁被释放之前,其他线程无法检查队列的状态。