比特币源码研读之三
自从发表了两篇比特币源码研读总结系列之后,很多朋友都表示对编程和研读源码产生了兴趣,有些朋友提出想加入我们区块链研习社的源码研读班,参与比特币源码的研读、分析与讨论。我和社长看到大家这么积极都很开心,但鉴于第一期名额已满暂不对外开放,我们后续会开放一定名额,让更多人参与进来的,请大家关注我们的通知。
本文将继续沿着我们比特币核心后台进程的运行过程进行研读分析,话不多说,继续我们的征程!
本文主要涉及的源码文件包括:
src/bitcond.cpp、src/util.h、src/util.cpp、src/syn.h、src/syn.cpp、src/scheduler.h、src/ scheduler.cpp
一、应用程序初始化AppInit
AppInit函数是main函数执行的最后一个过程,我们通过该函数的注释(Start)以及AppInit函数的参数为main函数中的参数可知,其代表的是整个比特币后台进程真正开始运行的入口。
//////////////////////////////////////////////////////////////////////////////
//
// Start
//
bool AppInit(int argc, char* argv[])
在AppInit中包含了图中其后所有过程从上至下的调用。首先来看该函数在最开始定义了2个变量。
boost::thread_group threadGroup;
CScheduler scheduler;
boost::thread_group从其字面意思我们可以看出其为线程组,可以实现对多个线程统一管理。
CScheduler为比特币源码中定义的线程调度类,其定义头文件为src/Scheduler.h,实现文件为src/Scheduler.cpp。我们首先来看其头文件中对CSheduler类的解释与使用方法。
// Simple class for backgroundtasks that should be run
// periodically or once "aftera while"
//
// Usage:
//
// CScheduler* s = newCScheduler();
//s->scheduleFromNow(doSomething, 11); // Assuming a: void doSomething() { }
//s->scheduleFromNow(boost::bind(Class::func, this, argument), 3);
//boost::thread* t = newboost::thread(boost::bind(CScheduler::serviceQueue, s));
// ... then at program shutdown,clean up the thread running serviceQueue:
// t->interrupt();
// t->join();
// delete t;
// delete s; // Must be done afterthread is interrupted/joined.
本节先分析其注释的含义,该类主要用于对后台任务的管理,其管理对象为那些需要周期执行或在某时刻一次性运行的任务(可理解为线程)。
在CSChedule类的示例使用代码中,我们可以发现其包含了scheduleFromNow(现在执行某任务)、
boost::bind(CScheduler::serviceQueue, s));(线程与任务调度队列绑定, bind是绑定函数和函数的参数)等方法,所以可以看出,其主要是对比特币程序中的任务执行顺序进行设置,并针对执行顺序进行调度,具体使用方法将在后续实际使用时详细说明。
二、参数解析ParseParmeters
AppInit函数中执行的第一个函数为ParseParameters,通过其字面意思我们可以看出其主要功能为解析外部传入的参数。其实现代码位于src/util.cpp中。
(1)互斥锁
该函数的第一行代码为LOCK(cs_args);LOCK和cs_args都没有在该函数中定义,因此我们就需要查找其定义所在,以便我们理解其真正含义。通过查找cs_args定义位于src/util.cpp的上方,其定义为:
CCriticalSection cs_args;
CCriticalSection又为何物,有过线程编程经验的应该知道Critical Section为线程中的访问临界资源,多个线程必须互斥地对它进行访问,即保证在该代码后面的全局变量在程序运行过程中不会被其他线程对其后的变量进行篡改。那么CCriticalSection类在哪定义呢?通过查找发现其在src/sync.h中实现了定义,从定义可以看出该类继承自boost::recursive_mutex互斥类。
class CCriticalSection : publicAnnotatedMixin
{
public:
~CCriticalSection() {
DeleteLock((void*)this);
}
};
了解了cs_args为互斥类对象,我们再来看LOCK函数,其又为何物呢?我们再次来到src/sync.h,可以找到其定义如下。
#define LOCK(cs) CCriticalBlock PASTE2(criticalblock,__COUNTER__)(cs, #cs, __FILE__, __LINE__)
通过其定义,我们可以看出LOCK并不是一个单独的函数,而是一个宏定义,与前面的CCriticalSection对象结合实现对包含代码在各线程中进行互斥加锁处理,防止后续代码中涉及的全局变量被不同线程抢夺。
(2)参数解析
在互斥锁后,程序使用两个map对象实现了传入参数与其参数值的key-value式的映射存储。这两个对象分别为:
map<string, string> mapArgs;
static map<string, vector<string>> _mapMultiArgs;
mapArgs实现对单个参数及其对应值的映射存储,mapMultiArgs实现单个参数及其对应多个值的映射存储。
在使用这两个变量时,程序对其使用clear方法进行了清空操作。
mapArgs.clear();
_mapMultiArgs.clear();
随后通过for循环实现对所有参数进行逐个解析,获取参数及其值,对于存在多个值的参数mapArgs只存储最后的参数值,mapMultiArgs则将参数对应的所有的值通过vector变量进行存储。
至此完成了应用程序初始化的第一步:参数解析任务。在完成参数解析后,程序将完成相应参数的处理工作。具体处理过程,我将在下一篇源码分析文章中给出!
作者:区块链研习社比特币源码研读班 菜菜子
以下是广告:
我们区块链研习社已创建“区块链研习社币圈交流”小密圈”,在小密圈中,我们将带领大家一起学习区块链的原理与投资,还将提供区块链基本原理解答、交易所注册与交易操作、ICO交易与操作、投资分析、风险分析等内容。
目前入圈价格初始定价50元,50人调整一次价格,每次调整幅度为50元!