比特币源码阅读(二):初始化和启动(1)

入口函数

比特币源码阅读(二):初始化和启动(1)_第1张图片
main函数.jpg

在main()函数中,我们可以看到用SetupEnvironment()来准备环境,noui_connect()用来链接bitcoind的信号处理,AppInit()进行程序的基本初始化。

1. SetupEnvironment()

函数位置/src/util.cpp

//line: 797
void SetupEnvironment()
{
//1.判断操作系统并分配内存空间
#ifdef HAVE_MALLOPT_ARENA_MAX
    if (sizeof(void*) == 4) {
        mallopt(M_ARENA_MAX, 1);
    }
#endif
//2.在大多数POSIX系统环境的区域设置可能无效,所以在区域设置之前判断操作系统
#if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
    try {
        std::locale(""); 
    } catch (const std::runtime_error&) {
        setenv("LC_ALL", "C", 1);
    }
#endif
//3.初始化本地文件系统流
    std::locale loc = boost::filesystem::path::imbue(std::locale::classic());
    boost::filesystem::path::imbue(loc);
}
  1. 通过sizeof(void *) == 4判断系统是否为32位,64位系统的结果为8。
    mallopt(M_ARENA_MAX, 1)glibc为了解决多线程内存分配竞争的问题,使用了很多叫做arena的memory pool。每一个arena都会占用一定的内存,设置的越多自然占用的内存也就多,线程的竞争就会越小,需要自己来测试程序的性能来合理的设置arena的个数。glibc会为每个核创建2个arena,这会对32位系统造成虚拟地址空间不足的问题,所以设置为1.
    如果想要关闭则可以设置成0,表示系统按CPU进行自动设置。

  2. 设置系统的区域,这将决定程序所使用的当前语言编码、日期格式、数字格式、及其他与区域相关的设置。本地化设置不成功就回退。
    LC_ALL它是一个宏,如果该值设置了,则该值会覆盖所有LC_*的设置值。注意,LANG的值不受该宏影响。
    "C"是系统默认的locale,"POSIX"是"C"的别名。所以当我们新安装完一个系统时,默认的locale就是C或POSIX。

  3. std::locale::classic()返回经典区域设置,经典格式经常用于读写数据文件。
    每个I/O流都有自己的locale对象,要改变流的locale,可以调用他的imbue函数,将locale对象作为唯一的参数传入。
    换言之,在C++启动的时候,他会用经典区域设置初始化每个流

2. noui_connect()

函数位置/src/noui.cpp

void noui_connect()
{
    // Connect bitcoind signal handlers
    uiInterface.ThreadSafeMessageBox.connect(noui_ThreadSafeMessageBox);
    uiInterface.ThreadSafeQuestion.connect(noui_ThreadSafeQuestion);
    uiInterface.InitMessage.connect(noui_InitMessage);
}

ThreadSafeMessageBox、ThreadSafeQuestion、InitMessage三个变量和全局变量uiInterface定义在/src/ui_interface.h,我们看下代码

/** Show message box. */
boost::signals2::signal > ThreadSafeMessageBox;

/** If possible, ask the user a question. If not, falls back to ThreadSafeMessageBox(noninteractive_message, caption, style) and returns false. */
boost::signals2::signal > ThreadSafeQuestion;

/** Progress message during initialization. */
boost::signals2::signal InitMessage;

/* 声明全局变量uiInterface */
extern CClientUIInterface uiInterface;  

signals2基于Boost的另一个库signals,实现了线程安全的观察者模式。在signals2库中,观察者模式被称为信号/插槽(signals and slots),他是一种函数回调机制,一个信号关联了多个插槽,当信号发出时,所有关联它的插槽都会被调用。
可以看做事件的回调机制。通过connect()函数来调用回调函数。相当于为信号(事件)增加了一个处理的handler。
参考: http://blog.csdn.net/zengraoli/article/details/9697841
注意:这里定义的参数一定要和你定义的回调函数的参数保持一致。

所以当接收到对应的信号时,会进入回调函数来对信号进行处理,下面我们看一下noui_ThreadSafeMessageBox的代码:

static bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
{
    bool fSecure = style & CClientUIInterface::SECURE;
    style &= ~CClientUIInterface::SECURE;

    std::string strCaption;
    // Check for usage of predefined caption
    switch (style) {
    case CClientUIInterface::MSG_ERROR:
        strCaption += _("Error");
        break;
    case CClientUIInterface::MSG_WARNING:
        strCaption += _("Warning");
        break;
    case CClientUIInterface::MSG_INFORMATION:
        strCaption += _("Information");
        break;
    default:
        strCaption += caption; // Use supplied caption (can be empty)
    }

    if (!fSecure)
        LogPrintf("%s: %s\n", strCaption, message);
    fprintf(stderr, "%s: %s\n", strCaption.c_str(), message.c_str());
    return false;
}

通过代码我们可以看到。程序以打印日志和写入文件的方式来处理接收到的信号。

注意:ThreadSafeMessageBox中出现c_str()函数,这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成c中的字符串样式。

你可能感兴趣的:(比特币源码阅读(二):初始化和启动(1))