一 nodeos工作執行緒
nodeso節點的工作執行緒包括:乙個主線程,乙個訊號處理執行緒和兩個執行緒池。
主線程:main函式啟動執行緒,該執行緒執行完程式初始化工作後,會呼叫app().io_service.run(), 啟動boost::asio::io_service的非同步io服務,通過非同步io方式完成節點塊生產,交易處理等主要業務工作。
訊號處理執行緒:子執行緒,通過非同步io服務,接收系統訊號並處理。
執行緒池,執行緒池啟動的工作執行緒數可通過啟動引數配置。
controller執行緒池: 非同步執行塊block_state建立,塊中交易驗證時的交易解簽名計算。
生產者外掛程式執行緒池:負責非同步執行交易解簽名計算。
? 採用預設配置(每個執行緒池2個工作執行緒),nodeos節點匯流排程數是6個,通過pstree命令可檢視:
? nodeos有乙個主線程pid=32385,該主線程有5個子執行緒,32386~32390。
二 主線程
? main函式執行執行緒:main函式最後呼叫app().exec(),啟動io_service服務。
app()是application例項,application中定義了io_service物件io_serv:
class application
application::application():my(new application_impl())
boost::asio::io_service& get_io_service()
//啟動io服務
void application::exec()
void application::quit()
其它外掛程式通過get_io_service()函式,獲取io_serv,進行非同步io投遞。
程式退出時,會呼叫quit()函式,結束io服務。
? nodeos節點交易處理,出塊,塊驗證等主要業務操作都是在該執行緒執行的,因為eos中交易不支援並行處理,所以application中的io_serv是不允許在除主線程之外的其它執行緒中重複執行io_serv.run()操作的。
? 看到application::exec()中的**,有些人可能會有疑問:asio::io_service監聽的io埠都完成(沒有待監聽的io埠)時,io_serv->run()就會退出。這裡io_serv->run()只呼叫了一次,沒有迴圈呼叫,不會退出麼?
? nodeos投遞到application::io_serv的io處理handle函式,會重複投遞該io埠。所以在handle處理函式完成時,io_serv中總會有待完成io存在,io_serv->run()就不會退出,下面以producer_plugin中的_timer為例,看一下這個投遞過程:
producer_plugin::producer_plugin()
: my(new producer_plugin_impl(app().get_io_service()));
class producer_plugin_impl
boost::asio::deadline_timer _timer;
};? producer_plugin()在構造時傳入app().get_io_service()構造了producer_plugin_impl:: _timer; 在節點的生產迴圈函式中可以看到, _timer的handle函式中會呼叫schedule_production_loop()函式,而在該函式中,又會呼叫 _timer.asyncwait()重複投遞 _timer到ioservice中:三 訊號處理執行緒
建立io_service物件sig_io_serv;
將sigint訊號投遞到io_service物件,並繫結訊號處理函式,當系統傳送sigint訊號時,會觸發該處理函式。
建立sig_thread訊號處理執行緒,在該執行緒中呼叫sig_io_serv->run(),等待訊號觸發,呼叫相應處理函式。
訊號處理執行緒只處理sigint,sigterm,sigpipe這三個系統訊號,一旦收到訊號,會呼叫退出操作,使nodeos退出。
四 controller執行緒池
4.1 定義及建立
struct controller_impl
controller_impl( const controller::config& cfg, controller& s ):self(s),
chain_id( cfg.genesis.compute_chain_id() ),
read_mode( cfg.read_mode ),
...thread_pool( cfg.thread_pool_size )
controller執行緒池定義在controller_impl中;
根據配置引數中設定的thread_pool_size建立相應數量的工作執行緒。
4.2 非同步任務
? 執行塊相關操作時,較耗時且與排序無關的動作都會投遞到controller執行緒池執行。eos目前投遞到該執行緒池執行的操作有兩個:
? 1 塊交易驗證時的解簽名操作;
? 2 塊狀態block_state資料建立操作(兩輪共識計算都在這裡完成)。
4.2.1 解簽名操作
? 節點收到塊,會呼叫apply_block()函式執行塊中交易,進行塊驗證。期間會投遞交易解簽名計算到controller執行緒池:
? 解簽名投遞函式create_signing_keys_futrue():
**程池thread_pool中非同步執行解簽名函式,非同步解簽名的執行結果,會放入交易的signing_keys_future中。
真正解簽名演算法是trn.get_signature_keys(),解出的公鑰放到recovered_pub_keys中。
4.2.2 block_state建立
五 生產者執行緒池
5.1 定義及建立
? 生產者執行緒池定義在producer_plugin_impl中,執行外掛程式初始化函式plugin_initialize()時會根據配置引數建立工作執行緒。
class producer_plugin_impl : public std::enable_shared_from_this
void producer_plugin::plugin_initialize(const boost::program_options::variables_map& options)
5.2 非同步任務
? 生產者執行緒池負責的工作任務有兩個:
1. 為接收到的投遞交易進行非同步解簽名計算;
2. 等待解簽名計算完成,將交易投遞到主線程的非同步io服務中處理。
? 這兩個工作任務都在同乙個函式中投遞執行:該函式在節點收到其它節點/客戶端投遞的交易時被呼叫:
投遞非同步解簽名計算任務到 _threadpool執行緒池( 生產者執行緒池),計算結果放到
trx->signing_keys_future中。
投遞非同步任務到 _thread_pool執行緒池,該任務等待將非同步解簽名計算結束的交易投遞到主線程的io_service中執行。
5.3 執行緒池關閉
? 當呼叫外掛程式shutdown函式時,會執行執行緒池關閉動作,前程池中的工作執行緒退出。
六 鏈結
星河公鏈
依託於區塊鏈的TD源鏈究竟有什麼特性
從物聯網 iot 融合到無銀行賬戶的初創企業,都表達了對2019年區塊鏈的期望。自從中本聰satoshi著名的 將區塊鏈引入以來,已經有十多年了。這項技術已經遠遠超出了加密貨幣,影響了許多行業。我們將揭示為什麼無論數字貨幣發生什麼變化,區塊鏈都會記錄下來。區塊鏈的前景被廣泛看好,主要就是基於區塊鏈的...
區塊鏈研究總結 EOS
本文為區塊鏈技術總結及發展展望一文的子章節。業內對於誰是第三代區塊鏈系統代表還沒達成一致,不過eos絕對是個不可忽視的競爭者。eos致力於解決以太坊使用過程的一系列痛點,推動去中心化應用的發展。eos由bm github賬號bytemaster 通過史上最大規模ico專案發起,目標是成為區塊鏈世界的...
區塊鏈 EOS 環境的搭建
目錄概述 開始編譯並安裝 如上圖,目標是主要包含幾個工具 nodeos eos的核心部分,能夠提供各種api服務,能夠同步節點。cleos 是用於給使用者操作的部分,只要nodeos配置好並執行後,都是通過cleos對其進行呼叫的 當然也可以呼叫別的節點的nodeos介面 keosd 用於安全儲存使...