深入V8引擎-初始化默认Platform(1)
本来寻思着写一篇"'hello' + ', world'"是怎么从js代码编译然后输出的,然而compile过程的复杂性远超我的想象,强上怕会走火入魔,还是老老实实先回家种田,找点咸鱼方法先写着。虽然说是咸鱼方法,但是v8任何一块拿出来都不简单,之前讲的time模块说实话大概是属于源码里面幼儿园级别的,这次试试难一点的。
v8的源码在本地编译完成后,会提供一个的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对象),这个类主要负责管理线程池、调用栈、事件队列等一些杂活。
这一篇不会去深入方法一步一步走,里面内容太过于杂乱,跳来跳去的,先整体介绍一下所有涉及的类,有一个初步的印象(建议深入阅读所有基类的英文注释,解释的很明白)。
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 handletask() { // 新建一个task auto task = new usertask(); // 加入队列 queue_.push_back(task); // 唤醒线程 thread_.signal(); // 线程处理task while(true) { if(queue_.empty()) break; auto task = queue_pop_back(); task->run(); } // 线程等待唤醒 thread_.wait(); }
过程跟其实libuv的异步操作差不多,感觉编程的套路也就那样,看多了源码或者有实际开发经验的都熟悉。
这一篇就先介绍一些类(调用栈和内存管理先放着),了解后基本上v8中关于platform的内容就差不多了。关于thread、taskrunner、task三者的联系与运作,因为c++是速成的,没去了解这些东西的实际运用,所以暂时不在这里班门弄斧了。之前学java的时候了解过线程,感觉无论是api的名字还是概念都差不多,有兴趣的可以自己去看看。
上一篇: AI中怎么制作渐变点状漩涡logo?
下一篇: 以时间作为条件查询记录(案例)