本来寻思着写一篇 "'Hello' + ', World'" 是怎么从 JS 代码编译然后输出的, 然而 compile 过程的复杂性远超我的想象, 强上怕会走火入魔, 还是老老实实先回家种田, 找点咸鱼方法先写着. 虽然说是咸鱼方法, 但是 V8 任何一块拿出来都不简单, 之前讲的 Time 模块说实话大概是属于源码里面幼儿园级别的, 这次试试难一点的.
V8 的源码在本地编译完成后, 会提供一个 hello-world.cc 的 sample, 里面有新手用户标准的初始化流程, 如下.
- int main(int argc, char* argv[]) {
- // Initialize V8.
- // 这个方法在 Mac 不作为
- v8::V8::InitializeICUDefaultLocation(argv[0]);
- // 读取指定名称的配置文件 也不用鸟
- v8::V8::InitializeExternalStartupData(argv[0]);
- // 生成一个默认的 platform 对象
- std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
- // 初始化刚才的 platform
- v8::V8::InitializePlatform(platform.get());
- // V8 的初始化
- v8::V8::Initialize();
- // ...
- }
前两步不用去管, 在入门阶段用不上.
第三步是主要内容, 探究生成的默认 platform 对象 (当然也可以选择自己定制一个 platform 对象), 这个类主要负责管理线程池, 调用栈, 线程 task 等一些杂活.
这一篇不会去深入方法一步一步走, 里面内容太过于杂乱, 跳来跳去的, 先整体介绍一下所有涉及的类, 有一个初步的印象 (建议深入阅读所有基类的英文注释, 解释的很明白).
Platform
首先当然是核心类 Platform, 但这是一个基类, 里面的大部分方法都是虚函数.
- /**
- * V8 Platform abstraction layer.
- *
- * The embedder has to provide an implementation of this interface before
- * initializing the REST of V8.
- */
- class Platform {};
如果需要定制 platform 来初始化 V8, 需要继承这个类并实现那些方法. 一般情况下当然可以 V8 默认提供的类, 即 DefaultPlatform.
- class DefaultPlatform : public Platform {
- public:
- // 接受一个枚举值, 一个 TracingController 类的构造函数
- explicit DefaultPlatform(
- IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled,
- std::unique_ptr<v8::TracingController> tracing_controller = {});
- ~DefaultPlatform() override;
- // 设置线程池大小
- void SetThreadPoolSize(int thread_pool_size);
- // 初始化线程池, 管理线程任务相关的方法
- void EnsureBackgroundTaskRunnerInitialized();
- private:
- // 最大线程池数量 默认为 8
- static const int kMaxThreadPoolSize;
- int thread_pool_size_;
- IdleTaskSupport idle_task_support_;
- // 线程任务启动器
- std::shared_ptr<DefaultWorkerThreadsTaskRunner> worker_threads_task_runner_;
- // 工具类
- std::unique_ptr<TracingController> tracing_controller_;
- std::unique_ptr<PageAllocator> page_allocator_;
- // 计数方法 用的是之前介绍的 Time 模块
- TimeFunction time_function_for_testing_;
- };
- /**
- * V8 Tracing controller.
- *
- * Can be implemented by an embedder to record trace events from V8.
- */
- class TracingController {};
- /**
- * A V8 memory page allocator.
- *
- * Can be implemented by an embedder to manage large host OS allocations.
- */
- class PageAllocator {};
只选了一些初始化相关的方法, 其实内容远比这个要多. 其中还定义了两个类似于 Platform 的基类变量, 一个负责调用栈追踪, 一个负责内存管理.
TaskRunner/Thread
接下来是任务执行者, 线程, 因为这两者基本上成对出现, 所以放一起来看.
- // Thread
- //
- // Thread objects are used for creating and running threads. When the start()
- // method is called the new thread starts running the run() method in the new
- // thread. The Thread object should not be deallocated before the thread has
- // terminated.
- class V8_BASE_EXPORT Thread {
- public:
- // Start new thread by calling the Run() method on the new thread.
- void Start();
- // ...
- };
这是最基础的 Thread, 其中定义并实现了 Start 等常规方法, 也有一些虚函数需要继承去重新实现, 除此之外还有一些静态方法. 默认情况下, V8 自定义了一个线程类继承于基本 Thread, 位置十分的隐蔽, 在默认 TaskRunner 的 private 里面.
- /**
- * A TaskRunner allows scheduling of tasks. The TaskRunner may still be used to
- * post tasks after the isolate gets destructed, but these tasks may not get
- * executed anymore. All tasks posted to a given TaskRunner will be invoked in
- * sequence. Tasks can be posted from any thread.
- */
- class TaskRunner {};
- class DefaultWorkerThreadsTaskRunner : public TaskRunner {
- public:
- using TimeFunction = double (*)();
- DefaultWorkerThreadsTaskRunner(uint32_t thread_pool_size, TimeFunction time_function);
- private:
- class WorkerThread : public Thread {
- public:
- explicit WorkerThread(DefaultWorkerThreadsTaskRunner* runner);
- ~WorkerThread() override;
- // This thread attempts to get tasks in a loop from |runner_| and run them.
- void Run() override;
- private:
- DefaultWorkerThreadsTaskRunner* runner_;
- };
- // 获取下一个 task
- std::unique_ptr<Task> GetNext();
- bool terminated_ = false;
- // task 队列
- DelayedTaskQueue queue_;
- // 线程池
- std::vector<std::unique_ptr<WorkerThread>> thread_pool_;
- // 计数方法
- TimeFunction time_function_;
- std::atomic_int single_worker_thread_id_{0};
- uint32_t thread_pool_size_;
- };
这里顺便把 TaskRunner 相关的内容也一并放出来, 大部分内容可以看命名. 内部类的初始化参数类型是外部类, V8 完全把 Thread,TaskRunner 两个类绑起来了.
Task
这个类只是一个简单基类.
- /**
- * A Task represents a unit of work.
- */
- class Task {
- public:
- virtual ~Task() = default;
- // 所有的 task 需要继承这个类并实现 Run 方法
- virtual void Run() = 0;
- };
由于 HelloWorld 的 sample 并没有用到多线程, 所以不存在 Task 类的实现, 这里只能先关注概念. 使用时, 大概方法如下, 写个伪代码演示下.
- class userTask : public Task {
- public:
- void Run() {
- // do something...
- };
- };
- void handleTash() {
- // 新建一个 task
- auto task = new userTask();
- // 加入队列
- queue_.push_back(task);
- // 唤醒线程
- thread_.signal();
- // 线程处理 task
- auto task = queue_pop_back();
- task -> Run();
- // 线程等待唤醒
- thread_.wait();
- }
过程跟其实 libuv 的异步操作差不多, 感觉编程的套路也就那样, 看多了源码也就熟悉了.
这一篇就介绍类的概念, 了解后基本上 V8 中关于 Platform 的内容就差不多了. 关于 Thread,TaskRunner,Task 三者的联系与运作, 因为就学了 2 周 C++, 没去了解在 C++ 中这些东西的实现与运用, 所以暂时不在这里班门弄斧了. 之前学 Java 的时候了解过线程, 感觉无论是 API 的名字还是概念都差不多, 有兴趣的可以自己去看看.
来源: https://www.cnblogs.com/QH-Jimmy/p/10964223.html