比特幣源碼解析(2) - 準備知識 - Boost

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;

} 轉自:http://blog.csdn.net/pure_lady/article/details/77675915

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章