library使用注意macro define

在使用第三方函式庫時,要注意build library和use library(shared, static)的macro選項
例如:
CURL_STATICLIB
或是header only選項
cppnetlib BOOST_NETWORK_NO_LIB
另外是注意編譯時的macro define,有可能使用時須要一致。

以後有注意到再繼續補

Posted in Tips | Leave a comment

int() = 0

顯式的使用 int() 會回傳0
int a = int(); //a=0
這個在語法上看起來「像」是constructor,而效果上也很「像」constructor (default value = 0)

那麼這個語法的值是怎麼被決定的呢?
參考c++03

5.2.3 Explicit type conversion (functional notation)
 的第二點
 The expression T(), where T is a simple-type-specifier (7.1.5.2) for a non-array complete object type or
 the (possibly cv-qualified) void type, creates an rvalue of the specified type, which is value-initialized
 int是 simple-type-specifier
 那麼 什麼是value-initialized?
 參考 8.5 Initializers
 第五點
 To value-initialize an object of type T means
 ...
 — otherwise, the object is zero-initialized (int對應這條)
 
 To zero-initialize an object of type T means
 if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T; (int對應這條)
 ... 

在使用上配合template T()會有一致性,跟void()有異曲同工之妙
事實上這樣在使用STL 如map, vector時不用擔心primitive type的初始值

例如

std::map<char, int=""> x;
 x['a']++; //這樣子最後會是1
//也就不需要像下面這樣寫
if(x.find('a') == x.end())
{
  x['a'] = 1;
}
else
{
 x['a']++;
}
Posted in C++ Language | Leave a comment

reliability & availability

在系統設計中,有時會關注reliability, availability這兩個特性。reliability 是可靠度而availability是可用度。

這是兩個完全不同的概念(但要看定義)。在可靠度工程裡有比較嚴謹的數學定義,這邊只做qualitative概念性的描述。

Dependability, or reliability, describes the ability of a system or component to function under stated conditions for a specified period of time
(節錄 https://en.wikipedia.org/wiki/Reliability_engineering)

reliability 指的是系統在一段時間內是否正常運作,而availability指的是在一段時間內系統可以使用的時間比例 (這邊在不同的context下可能會有不同的定義方式,例如CAP裡論證的availability是以response time來定義availability)

a measure of the degree of a system which is in the operable and committable state at the start of mission when the mission is called for at an unknown random point in time. (參考https://en.wikipedia.org/wiki/Availability)

如果用生活的例子來說
high availability => 隨call可以隨到:
隨call(unknown random point in time)
隨到(operable and committable state)

而可靠度:

  • 某甲每個月按照約定(to function)按時繳貸款,連續20年(a specified period of time)
  • B覺得A是可靠的人,因為A總是(a specified period of time 從認識開始) 說到做到(function as expectation)

要達成high availability的方式最基本的思路是redundant,而要達成high reliability的方式比較複雜一點,如果做的事沒有side effect,那麼最基本的思路是consensus,這個再另文描述。

Posted in Distributed | Leave a comment

2PC – an interesting analogy

interesting analogy主要是後面提到的marriage vows描述,2PC (two phase commit 兩階段提交) 是在transaction processing裡的一種protocol,主要是為了要保證atomic operation,在transaction或database裡的atomic指的是 all occur, or nothing occurs. 在transaction裡一系列的操作生效 或是 當作沒發生過。2PC是在分布式系統中,需要transaction時的基本做法,有一些算法也是基於2PC所遇到的問題進行改良(如3PC)

2PC主要是提供在分布式環境多節點的atomic演算法,這邊的節點有可能是不同主機或process
舉例來說,銀行的轉帳,A帳戶的錢轉到B帳戶所需要的操作是
1. A扣掉轉的錢(&手續費)
2. B帳戶的錢增加
(這兩個操作可能是發生在不同地方的主機)

這兩個操作應當是視為一整體,也就是當使用者按下確認轉帳後 因為某些原因如網路或設備故障造成交易無法完成時,系統必須回復到交易前的狀態(就如同沒發生過),否則可能會造成A帳戶的錢扣了,而B帳戶的錢沒增加。

因為假設操作節點有可能故障,這樣的設計必須是可以failure recovery的,當失敗時可以回復狀態(無論是多節點中其他節點的失敗或是自己本身的故障如斷電),要能夠進行這樣的recovery 必須要有durability來紀錄操作歷史以便復原。所以一般會用redo log, undo log紀錄操作在非揮發性的儲存上面。

另外因為牽涉多節點的協調,所以很自然會有一個協調者的角色。這個協調者通知與蒐集所有節點的回報來確認操作是否成功或失敗。(commit or abort)

這個演算法分成兩階段
1. commit-request phase / voting phase:

  • coordinator 對 所有的節點發出transaction operation request,並等待回應 (以上面的例子來說 對A帳戶的銀行主機發出扣款,B帳戶的主機發出新增款項的操作,可以有先後順序-causality而非并行)
  • 節點要執行request的操作,並且記錄undo/redo log
  • 回覆成功或失敗 (譬如說 A帳戶餘額不足)

2. commit phase 分成兩種case:

success

  • 全部的節點在phase 1都說OK, coordinator再發出commit要求到每個節點
  • 節點完成commit後釋放資源回覆ACK
  • 當coordinator收到所有ACK後,transaction完成

failure

  • 有節點在phase 1說NOT OK 或是coordinator沒收到全部回應(timeout)
  • 送出rollback要求給每個節點
  • 節點完成rollback(undo)後後釋放資源回覆ACK
  • 當coordinator收到所有ACK後,transaction取消

2PC的缺點:

  • 過程是blocking的: 當節點回應OK後 等待commit or rollback的期間,資源會占住(以銀行的例子就是該帳戶的餘額是被鎖定的,所以無法再處理會更動金額的要求)
  • 當coordinator fails可能會造成 節點的無限等待
  • phase 2如果節點沒有ACK的error handling

關於2PC有一個生動的例子可以描述:

結婚儀式作為一個transaction:
要嘛結婚儀式完成(commit->已結婚狀態) 要嘛取消(abort->回到原來未婚的狀態)
coordinator: 神父或牧師
participants: 一對新人

phase 1:
coordinator發出request:
A先生,無論貧窮、疾病、困難、痛苦,富有、健康、快樂、幸福,你都願意對B小姐不離不棄,一生一世愛護她嗎?
B小姐,無論貧窮、疾病、痛苦、富有、健康、快樂、幸福,你都願意對A先生不離不棄,一生一世愛護他嗎?
phase 2:
收集A, B response
如果A B 皆回答I do. (OK) 那就宣告成為夫妻 (send commit)
接下來雙方交換信物戒指 可視為commit成功的ACK

可是以上是success的情況 可以想一想:

  • 如果有一方說No 那應該如何處理…神父或牧師就會發出rollback request~~
  • 如果有一方想很久 一直沒回應I do….宣布timeout, rollback
  • 但還有一種情況是coordinator出現異常…譬如說神父或牧師突然昏倒了…在2PC的流程裡 沒有處理這種case,
    所以可能會讓台上的人陷入等待…(leader election Paxos算法有處理,選出下一位coordinator來接手,配合participant的狀態繼續request處理,但整體來說無法類比到這個情境..)

上面的例子主要是要說明 transaction的應用其實在生活中也能夠找到蹤影!

上面這個例子是在在找Paxos演算法的相關資料時,看到
https://www.quora.com/In-distributed-systems-what-is-a-simple-explanation-of-the-Paxos-algorithm
其中提出來的marriage vows的描述,並加以延伸。

參考:
https://en.wikipedia.org/wiki/Two-phase_commit_protocol

Posted in Distributed | Leave a comment

gcc turn off exceptions:-fno-exceptions

在g++編譯時,程式若為了效能考量可能希望減少執行時對exception機制的overhead,可用-fno-exceptions 這個選項關掉exception
但此時就無法使用try catch 可用 #if __cpp_exceptions 來做處理,
或是使用c processor的predefined macro

https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
__EXCEPTIONS
This macro is defined, with value 1, when compiling a C++ source file with exceptions enabled. If -fno-exceptions is used when compiling the file, then this macro is not defined.

int main()
{
 #if __cpp_exceptions
  throw "123";
 #endif
}

g++ -fno-exceptions test.cc
關掉exception後就不可以用try catch throw了

若不用exception機制時 則要小心所使用的library是否會拋出exception
以g++的libstdc++來說 利用macro處理 try catch throw等 可在編譯(libstdc++)時關掉exception
在bits/exception_defines.h (libstdc++-v3\libsupc++\exception_defines.h)

#ifndef __EXCEPTIONS
// Iff -fno-exceptions, transform error handling code to work without it.
# define __try      if (true)
# define __catch(X) if (false)
# define __throw_exception_again
#else
// Else proceed normally.
# define __try      try
# define __catch(X) catch(X)
# define __throw_exception_again throw
#endif

這時在STL library的throw 在-fno-exceptions之下會呼叫abort()
參考libstdc++-v3/src/c++11/functexcept.cc _GLIBCXX_THROW_OR_ABORT

但注意 編譯選項-fno-exceptions 只是當下編譯的選項,而有些library原本在編譯時是啟用exception的,程式link library object以後如果有exception,結果會是程式接不到exception而中止

因libstdc++.so 預設有exception,所以儘管有-fno-exceptions,使用到stl有exception時一樣會中止
除非是對STL另外編譯no exception版本,雖然一樣是abort()
這樣變得使用STL反而會要考慮底層的function是否會產生exception,反而是負擔了~

-fno-exceptions 這種情況比較適合是使用C的library 把C++當成better C來使用,或是使用的函式庫是在可以掌握不會有exception的情況下才適合使用

Posted in Tips | Leave a comment

VS2015 – copy header files

use post build event

利用帶入巨集變數$(SolutionDir),在powershell script讀取SolutionDir

powershell -ExecutionPolicy Unrestricted $(SolutionDir)\copyheader.ps1 -SolutionDir $(SolutionDir)

copyheader.ps1

param([string]$SolutionDir);
$src1 = $SolutionDir + "Http"
$dest1 = $SolutionDir + "output\http"
Copy-Item -Path $src1 -Filter "*.h" -Recurse -Destination $dest1 -Container -force

-force 強制overwrite
這樣會recursive的複製.h檔到對應的目錄

試過xcopy bat,比較起來powershell script處理方式較簡潔

Posted in Tips | Leave a comment

protected destructor

constructor access modifier 一般設為public,而在singleton中,為了限制生成的物件個數,會將constructor放在private,另外在其他method生成物件。而對於destructor,以Meyers Singleton的實作來說,destructor放在public or non-public皆可,因為static object 在宣告的地方可以存取到private destructor(參考下面12.4)

C++03 std
§3.6.3 Termination
Destructors (12.4) for initialized objects of static storage duration (declared at block scope or at namespace scope) are called as a result of returning from main and as a result of calling exit (18.3).
§12.4 Destructors
A program is ill-formed if an object of class type or array thereof is declared and the destructor for the class is not accessible at the point of the declaration.

ill-formed = not well-formed
well-formed = §1.3.14 a C + + program constructed according to the syntax rules, diagnosable semantic rules, and the One Definition
Rule

那麼什麼時候需要用到protected or private destructor呢?
在不希望物件被建立在stack上時,例如以下情形

class A
{
  ~A()
  {
  }
};
int main()
{
  A x; // A* x = new A;是可以的
  return 0;
}

以上編譯時會出現

test.cc: In function ‘int main()’:
test.cc:3: error: ‘A::~A()’ is private
test.cc:9: error: within this context

限制了在stack上生成,而A* x = new A; 則不會有問題,只要不要顯式的在外部呼叫delete
事實上要限制物件不能生成在stack上比較直覺的方式應該要透過constructor來控制,
利用factory method返回new 的結果即可

而private destructor 和protected destructor的差別是在當類別有繼承時
在基類的protected destructor可以避免使用者用基類的指標delete

private destructor會使derived class沒辦法delete 或是顯式定義destructor,造成繼承上的困難(除非在derived class不顯式定義destructor)。

Posted in C++ Language | Leave a comment

object slicing

object slicing發生在衍生類別的物件複製到基類時,預設只複製基類的成員,這時候在衍生類別的資訊會遺失。

這樣有可能造成在執行method或是destructor因為遺失了資訊而造成其他錯誤。
當複製為參考時(base class reference type),則不會有此問題。

object slicing的問題,在exception catch時要特別注意,應該要catch reference(catch(A& a)才不會造成object slicing),而不是catch value

如下面範例: 如果是 catch(A a) 會走copy ctor的路,因為是將B()複製到a,而造成object slicing,並且因為copy後,catch到的物件已經不是當時拋出的那個物件了

#include <iostream>

class A
{
public:
  A(const A&)
  {
    std::cout << "A(const A&):" << this <<std::endl;
  }
  A()
  {
    std::cout << "A():" << this <<std::endl;
  }
};

class B: public A
{
public:
  B(const B&)
  {
    std::cout << "B(const B&):" << this <<std::endl;
  }
  B()
  {
    std::cout << "B():" << this <<std::endl;
  }
};

int main()
{
  try
  {
    throw B();
  }
  catch(A a)
  {
    std::cout << "catch A" << std::endl;
  }
  return 0;
}

參考:
https://en.wikipedia.org/wiki/Object_slicing
https://stackoverflow.com/questions/274626/what-is-object-slicing
http://ptgmedia.pearsoncmg.com/images/0321113586/items/sutter_item73.pdf

Posted in C++ idioms | Leave a comment

std::make_shared

//C++11中的 shared_ptr初始化一般使用
std::shared_ptr p(new A);
//但也可以
std::shared_ptr p = std::make_shared();

使用make_shared可以避免顯式地使用new,另外主要的差別在make_shared 一般會將shared_ptr內的control block和object一起allocate。雖然一次allocate上比較有效率,但如果有用到weak_ptr,當shared count = 0時,不會馬上還回記憶體,因為control block還需要用到,而是要等到沒有任何shared_ptr, weak_ptr參考時,才會釋放記憶體。

在N3690文件 20.9.2.2.6 shared_ptr creation 中提到:

Remarks: Implementations should perform no more than one memory allocation. [ Note: This provides efficiency equivalent to an intrusive smart pointer. — end note ]
[ Note: These functions will typically allocate more memory than sizeof(T) to allow for internal bookkeeping structures such as the reference counts. — end note ]

參考:
https://isocpp.org/files/papers/N3690.pdf
http://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared

Posted in C++ Language | Leave a comment

wait on thread creation

下面的範例是一般worker thread的做法,利用boost threadgroup,在程式一開始由一個thread進入(main thread),離開的時候也是一個thread
一般來說在創建thread時不需要等待thread被創建完成再往下走,不過這裡示範了當所有thread建立完成後main thread才繼續往下執行(透過condition variable, wait)
這麼做可以讓控制流變的簡潔,並且視thread group的threads為一整體,也能確保在start()完成之前不會執行stop()。

ThreadManager.h

#include 
#include 
#include 
#include 
#include 
class ThreadManager
{
  std::mutex m;
  std::condition_variable cv;
  int numThreads = 5; //non-static data member with initializer (C++11)
  int startCount = 0;
  bool bRunning = true;
  boost::thread_group threads;
  ThreadManager()
  {
  }
public:
  static ThreadManager& getInstance()
  {
    static ThreadManager m;
    return m;
  }
  void start()
  {
    for(int i = 0; i< numThreads; i++)
    {
      threads.create_thread([this]{
        int id = startCount;
        {
          std::lock_guard lk(m);
          startCount++;
          std::cout << "thread " << id << " created" << std::endl;
        }
        cv.notify_one();
        while(bRunning)
        {
          //do something
          std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
        std::cout << "thread " << id  << " finished" << std::endl;
      });
    }
    std::unique_lock lk(m);
    cv.wait(lk, [this]{return startCount == numThreads;});
    //這裡等到全部thread開始執行時才往下走
  }
  void stop()
  {
    std::cout << "stopping threads..." << std::endl;
    bRunning = false; //這邊最好要有memory fence
    threads.join_all();
    std::cout << "threads stopped" << std::endl;
  }
};

main.cpp

#include 
#include 
#include 
#include "ThreadManager.h"

int main()
{
  ThreadManager& tm = ThreadManager::getInstance();
  tm.start();
  std::cout << "threads created, wait 5 seconds and stop" << std::endl;
  std::this_thread::sleep_for(std::chrono::milliseconds(5000));
  tm.stop();
}
Posted in Tips | Leave a comment