1.  主页
  2. 区块链
  3. 正文

从零到壹学习比特币源码解析第一讲:准备知识-Boost

黎跃春

孔壹学院、ChainDesk创始人兼CEO

如果您有任何关于区块链的问题,可以加入区块链技术交流QQ群729666975(进群无需添加验证信息,直接点击下一步,等待管理员通过即可),我们会为您一一解答。

        从零到壹学习比特币源码解析为一个系列,一共11讲,包括准备知识、源码解析等。今天我们将为大家介绍从零到壹学习比特币源码解析第一讲:准备知识-Boost。话不多说,马上开启我们的比特币源码解析学习之旅。


课程学习,添加莉莉微信(kongyixueyuan)获取。

孔壹学院

Boost是一个开源、跨平台、功能强大的c++库,并且是除了stl外最常用的库,实现了很多基本操作,能让开发变得更加简单、快捷。下面我们就介绍bitcoin源码中主要用到的一些类,官方文档见:

https://www.boost.org/doc/libs/1_67_0/ 

Signals2

Signals2是基于Boost的另一个库Signals,实现了线程安全的观察者模式。而观察者模式又是指:定义对象间的一种一对多的依赖关系,当一个对象发生改变时,所有依赖于它的对象都将得到通知并自动更新。 而在Signals2库中,观察者模式又被称为信号/插槽(Signals and slots),官方文档对其解释为

The Boost.Signals2 library is an implementation of a managed signals and slots system. Signals represent callbacks with multiple targets, and are also called publishers or events in similar systems. Signals are connected to some set of slots, which are callback receivers (also called event targets or subscribers), which are called when the signal is “emitted.”Boost.Signals2库是一个改善的信号/插槽系统的实现。信号在类似的系统中也被称为发布者或者事件,表示多个回调目标。信号会和多个插槽相连,插槽也就是回调的接收者(也被称为事件目标或者订阅者),当信号发射的时候,所有关联的插槽都会被调用。Signals and slots are managed, in that signals and slots (or, more properly, objects that occur as part of the slots) can track connections and are capable of automatically disconnecting signal/slot connections when either is destroyed. This enables the user to make signal/slot connections without expending a great effort to manage the lifetimes of those connections with regard to the lifetimes of all objects involved.信号/插槽被设计成能够跟踪连接状态以及在双方任何一个被销毁时自动断开连接。这就使得用户能够方便的使用信号/插槽连接关系,而不用再去管理这种连接关系涉及的所有对象的生命周期。

通俗的来讲,信号就是一个触发器,插槽就是一些列的回调函数,当信号发射时,也就是触发器被触发的时候,所有的回调函数都会被调用。信号/插槽机制功能就是把这些功能相关的函数汇集到一起,在某一时刻,按顺序依次调用。

明白它要实现的功能之后,我们再来看一个简单的实例。

// example1.cpp#include #include "boost/signals2.hpp"using namespace std;void slot1(){  cout << "solt1 call" << endl;}void slot2(){  cout << "solt2 call" << endl;}int main(){  boost::signals2::signal sig;  // 定义信号  sig.connect(&slot1);  // 信号关联插槽  sig.connect(&slot2);  sig();  // 出发信号  return 0;}

运行:

$ g++ example1.cpp$ ./a.out# 运行结果solt1 callsolt2 call

一定要安装 boostUbuntu 16.04 LTS,使用命令sudo apt-get install libboost-all-dev安装完boostmac 使用命令 brew install boost 安装 boost

Bind

bind并不是一个单独的类或函数,而是非常庞大的家族,依据绑定的参数个数和要绑定的调用对象类型,总共有数十个不同的形式,但它们的名字都叫做bind,编译器会根据具体的绑定代码自动确定要使用的正确形式。

bind接受的第一个参数必须是一个科调用对象f,包括函数指针、函数引用、成员函数指针和函数对象,之后bind接受最多九个参数,参数的数量必须与f的参数数量相等,这些参数将被传递给f作为形参。

绑定完成后,bind会返回一个函数对象,它内部保存了f的拷贝,具有operator(),返回值类型被自动推导为f的返回值类型。在发生调用时,这个函数对象将把之前存储的参数转发给f完成调用。

简单来说,Bind的功能就是对一个函数绑定某些参数,其中参数有一个很重要的概念叫做占位符,被定义为从1到9,下面来看一个简单的实例。

// example2.cpp#include "boost/bind.hpp"#include #include using namespace std;int f(int a, int b){  return a+b;}int g(int a, int b, int c){  return a+b+c;}struct P{  int x, y;  P(int a=9, int b=8):x(a), y(b){}  void print(){    cout << "x:" << x << " y:" << endl;  }};int main(){  int x = 1, y = 2, z = 3;  cout << boost::bind(f, x, y)() << endl; // f(x, y)  cout << boost::bind(g, _1, _2, _3)(x, y, z) << endl; // g(x, y, z)  cout << boost::bind(g, x, _2, x)(z, y, x) << endl; // g(x, y, x), 占位符表示的是实际传入的第几个参数  vector

v(10);  for_each(v.begin(), v.end(), boost::bind(&P::print, _1)); // print: P.x , P.y,当引用成员函数时,占位符第一个总表示对象实例  return 0;}

运行:

$ g++ example2.cpp$ ./a.out# 运行结果364x:9 y:8x:9 y:8x:9 y:8x:9 y:8x:9 y:8x:9 y:8x:9 y:8x:9 y:8x:9 y:8x:9 y:8

Thread

线程,是各种项目中经常会用到的一个技术,而一般提到线程都会涉及到多线程,多线程当中最经典的问题就是同步访问共享资源,和其他几乎所有语言一样boost也是通过提供互斥锁来解决的,但不同的是boost提供了多个互斥类,使得项目可以更灵活的处理共享资源。

// example3.cpp#include "boost/thread.hpp"#include using namespace std;boost::mutex m_mutex;void wait(int sec){  boost::this_thread::sleep(boost::posix_time::seconds(sec));}void work(){  for(int i=0;i<5;i++){    wait(1);    cout << "id: " << 1 << " " << i << endl;  }}void work1(int id){  for(int i=0;i<5;i++){    wait(1);    cout << "id: " << id << " " << i << endl;  }}void work2(int id){  for(int i=0;i<5;i++){    m_mutex.lock();    cout << "id: " << id << " " << i << endl;    m_mutex.unlock();    /******** 其他互斥锁    boost::lock_guard lock(mutex);  lock_guard在内部构造和析构函数分别自动调用lock()和unlock(),所以能自动将当前域设为互斥访问区域。    更多资料请参考: http://zh.highscore.de/cpp/boost/multithreading.html    ********************/  }}int main(){  boost::thread th1(&work); //最简单的调用,不带任何参数  boost::thread th2(boost::bind(&work1, 2));   boost::thread th3(boost::bind(&work1, 3)); // bind的一个重要应用,绑定参数!这里两个线程不加任何互斥,打印出来的是乱序  boost::thread th4(boost::bind(&work2, 4));   boost::thread th5(boost::bind(&work2, 5)); // 4,5线程加简单的互斥锁,结果按次序打印  th1.join();  // 阻塞当前进程,等待调用线程完成,防止主线程先结束  th2.join();  th3.join();  th4.join();  th5.join();    return 0;}

运行:

$ g++ example3.cpp -lboost_thread-mt -lboost_system$ ./a.out# 运行结果id: 4 0id: 4 1id: 5 0id: 4 2id: 5 1id: 4 3id: 5 2id: 4 4id: 5 3id: 5 4id: id: id: 231   000id: id: 21 id:  131 1id: 2 2id: id: 13 2 2id: id: 2 13 id: 33 3id: id: id: 123   444

Chrono

Chrono是Boost库中用于时间处理的库,主要包含三个概念时间段(duration),时间点(time_point)和时钟(clock)。

// example4.cpp#include #include "boost/chrono.hpp"using namespace std;// durations 表示一段时间间隔typedef boost::chrono::hours hours;typedef boost::chrono::minutes minutes;typedef boost::chrono::seconds seconds;typedef boost::chrono::milliseconds milliseconds;typedef boost::chrono::microseconds microseconds;typedef boost::chrono::nanoseconds nanoseconds;// clock 表示当前时间,是在不断的变化typedef boost::chrono::system_clock system_clock;typedef boost::chrono::steady_clock steady_clock;typedef boost::chrono::high_resolution_clock high_resolution_clock;// time point 表示某一个具体的时间点typedef system_clock::time_point sys_tp;int main(){  hours h1(1);  minutes m1(1);  minutes m2 = h1 + m1; //  只能转化为更小的单位  cout << m2 << endl; // 61 minutes  hours h2 = boost::chrono::duration_cast(h1 + m1); //强制转换  cout << h2 << endl; // 1 hour  cout << system_clock::now() << endl;  return 0;}

运行:

$ g++ example4.cpp -lboost_chrono-mt$ ./a.out# 运行结果61 minutes1 hour1524449285833521000 nanoseconds since Jan 1, 1970

Program options

在编写命令行程序时,经常会碰到的一个问题就是参数解析问题,就是说我们在运行程序时给程序附上不同的参数值使得程序能够完成不同的功能。而boost中的program options就是用来处理命令行传入的参数的模块,使得程序更简洁高效。

// example6.cpp#include #include #include #include using namespace std;int main(int argc, char* argv[]){  using namespace boost::program_options;  options_description desc("Command line options");    // 定义描述选项: (选项全称,缩写), (参数类型->默认值),(描述)  desc.add_options()    ("help,h", "print help message")    ("person,p", value()->default_value("world"), "person name")    ("file,f", value< vector >(), "input file name");  variables_map vm;  // 存储传入的参数  store(parse_command_line(argc, argv, desc), vm);  // 根据描述选项解析参数  notify(vm);  if(vm.count("help")){    cout << desc << endl;    return 0;  }  cout << "Hello " << vm["person"].as() << endl;  if(vm.count("file")){    vector files(vm["file"].as< vector >());    cout << "Got " << files.size() << " files." << endl;  }  return 0;}

运行:

$ g++ example6.cpp -lboost_program_options$ ./a.out# 运行结果Hello world$ ./a.out -h# 运行结果Command line options:  -h [ --help ]                print help message  -p [ --person ] arg (=world) person name  -f [ --file ] arg            input file name  $ ./a.out -p Splay  # 运行结果Hello Splay

       

课程学习

添加莉莉老师微信kongyixueyuan

不要错过


课程学习方式

目前10000+人已关注加入我们

文章源自网友分享,如有侵权请联系删除