么设置线程名字我也不太想知道。
第二步的方法名就是运行线程的任务,调用链比较长,会来回在几个类之间穿梭,调用各自属性的方法。
// 3-7
void NotifyStartedAndRun() {
if (start_semaphore_) start_semaphore_->Signal();
// 3-8
Run();
}
// 3-8
void DefaultWorkerThreadsTaskRunner::WorkerThread::Run() {
runner_->single_worker_thread_id_.store(base::OS::GetCurrentThreadId(), std::memory_order_relaxed);
// 3-9
while (std::unique_ptr<Task> task = runner_->GetNext()) {
// 每一个task会实现自己的run函数
task->Run();
}
}
// 3-9
std::unique_ptr<Task> DefaultWorkerThreadsTaskRunner::GetNext() {
// 3-10
return queue_.GetNext();
}
不理清楚,这个地方真的很麻烦,绕得很,可以看顶部的继承图。总之,最后调用的是DefaultWorkerThreadsTaskRunner类上一个类型为DelayedTaskQueue类的GetNext方法,返回类型是Task类,V8只是简单定义了一个基类,实际运行时的task都需要继承这个类并实现其Run方法以便线程执行。
最后的最后,GetNext的逻辑其实可以参考libuv的逻辑,机制都大同小异,方法的源码如下。
// 3-10
std::unique_ptr<Task> DelayedTaskQueue::GetNext() {
base::MutexGuard guard(&lock_);
for (;;) {
/**
* 这一片内容完全可以参考libuv事件轮询的前两步
* 1、从DelayQueue队列中依次取出超过指定时间的task
* 2、将所有超时的task放到task_queue_队列中
* 3、从task_queue_中将task依次取出并返回
* 4、外部会调用task的Run方法并重复调用该函数
*/
double now = MonotonicallyIncreasingTime();
std::unique_ptr<Task> task = PopTaskFromDelayedQueue(now);
while (task) {
task_queue_.push(std::move(task));
task = PopTaskFromDelayedQueue(now);
}
if (!task_queue_.empty()) {
std::unique_ptr<Task> result = std::move(task_queue_.front());
task_queue_.pop();
return result;
}
if (terminated_) {
queues_condition_var_.NotifyAll();
return nullptr;
}
/**
* 1、当task_queue_队列没有task需要处理 但是delay_task_queue_有待处理task
* 这里会计算当前队列中延迟task中最近的触发时间 等待对应的时间再次触发
* 2、当两个队列都没有需要的事件
* 线程会直接休眠等待唤醒
*/
if (task_queue_.empty() && !delayed_task_queue_.empty()) {
double wait_in_seconds = delayed_task_queue_.begin()->first - now;
base::TimeDelta wait_delta = base::TimeDelta::FromMicroseconds(base::TimeConstants::kMicrosecondsPerSecond * wait_in_seconds);
bool notified = queues_condition_var_.WaitFor(&lock_, wait_delta);
USE(notified);
} else {
queues_condition_var_.Wait(&lock_);
}
}
}
哎……V8引擎不过如此。