比特币源码解析(2) - 准备知识 - Boost

比特币源码解析(2) - 准备知识 - Boost

。 https://blog.csdn.net/u012183589/article/details/77675915

0x00 简介

Boost是一个开源、跨平台、功能强大的c++库,并且是除了stl外最常用的库,实现了很多基本操作,能让开发变得更加简单、快捷。下面我们就介绍bitcoin源码中主要用到的一些类,官方文档见:http://www.boost.org/doc/libs/1_65_0/ ,其中的每一个类也都包含着非常强大的功能,所以也不是短短几章就可以介绍完的,这里就对他们的基本用法做些介绍,以便于理解比特币中的源码,同时文章中也会给出一些参考资料,便于更详细的理解。

提示:以下代码在Ubuntu 16.04 LTS环境下编译运行通过,测试的过程中主要遇到两个问题(1)undefined reference to boost::system::generic_category()等等类似未定义引用的错误,解决方法是g++ example.cpp -lboost_system -lboost_thread也就是在编译参数后面加上链接库,根据错误添加相应的库。(2)template argument deduction/substitution failed这个错误是因为写的函数名和系统的函数名冲突了,比如你程序中定义了一个void count(){}函数,编译的过程就会出现这个错误,网上的boost thread教程很多都定义了count函数做示例,那些例子至少在Ubuntu环境下跑不通的,所以函数名尽量不要起容易冲突的名字,就算出现了类似错误也可以尝试修改一下函数名。

0x01 Signals2

这部分的介绍主要参考: http://blog.csdn.net/zengraoli/article/details/9697841

Signals2是基于Boost的另一个库Signals,实现了线程安全的观察者模式。而观察者模式又是指:定义对象间的一种一对多的依赖关系,当一个对象发生改变时,所有依赖于它的对象都将得到通知并自动更新。(http://blog.csdn.net/wuzhekai1985/article/details/6674984 ) 而在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 <iostream>
#include "boost/signals2.hpp"
using namespace std;

void slot1(){
  cout << "solt1 call" << endl;
}

void slot2(){
  cout << "solt2 call" << endl;
}

int main(){
  boost::signals2::signal<void()> sig;  // 定义信号
  sig.connect(&slot1);  // 信号关联插槽
  sig.connect(&slot2);
  sig();  // 出发信号
  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

我的运行环境是Ubuntu 16.04 LTS,使用命令sudo apt-get install libboost-all-dev安装完boost之后,即可直接使用g++ example1.cpp编译运行。

以上只是对Signals2用法的简单介绍,涉及到的也只是Signals2的九牛一毛,更详细的用法还请各位同学自行查阅相关资料。

0x02 Bind

这部分参考:http://blog.csdn.net/zengraoli/article/details/9666943

首先引用上面博客对Bind的介绍:

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

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

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

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

// example2.cpp
#include "boost/bind.hpp"
#include <iostream>
#include <vector>
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=9):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<P> v(10);
  for_each(v.begin(), v.end(), boost::bind(&P::print, _1)); // print: P.x , P.y,当引用成员函数时,占位符第一个总表示对象实例
  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

0x03 Thread

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

// example3.cpp
#include "boost/thread.hpp"
#include <iostream>
using namespace std;

boost::mutex 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++){
    mutex.lock();
    cout << "id: " << id << " " << i << endl;
    mutex.unlock();

    /******** 其他互斥锁
    boost::lock_guard<boost::mutex> 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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

0x04 Chrono

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

// example4.cpp
#include <iostream>
#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<hours>(h1 + m1); //强制转换
  cout << h2 << endl; // 1 hour

  cout << system_clock::now() << endl;
  return 0;
}

没有更多推荐了,返回首页