mutex 用來保護多個 thread 共享(shared)的資料,避免 concurrent modification 造成問題。

lock mutex => modify shared data => unlock mutex

mutex 有三種 type:

  1. fast
  2. recursive
  3. error check

操作 mutex 的 function 會依照 type 不同而可能有不同的操作方式。

Initialize Mutex

initial 時,可以用 pthread_mutex_init() 或直接 assign const 指定 mutex 的 type。

1
2
3
4
5
6
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);

// 直接 assign const
pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;

Lock Mutex

1
pthread_mutex_lock()

如果 mutex 是 unlock 狀態,則 lock 該 mutex 且讓該 mutex 為 call phread_mutex_lock() 的 thread 擁有,做完這些後立刻 return。

如果 mutex 正被 lock 住,此 function 會依照不同 type 的 mutex 有不同動作:

  1. fast

    calling thread 會 suspend,直到 mutex unlock。沒寫好的話可能造成 deadlock。

  2. recursive

    成功並立刻 return。這種 mutex 會記錄它被 lock 幾次,也就是一個 thread 可以 lock 這種 mutex 很多次。要 unlock 這種 mutex 時,也必須 call 相應 lock 次數的 unlock function 才能真正 unlock。

  3. error check

    立刻 return,但 errno = EDEADLK。真是個會讓人誤會的 errno 名稱…

    EDEADLK 在 man page 的解釋:

    the mutex is already locked by the calling thread (``error checking’’ mutexes only).

Try Lock Mutex

1
pthread_mutex_trylock()

跟 pthread_mutex_lock() 差不多,差別是這個不會 block 住。

操作 fast mutex 時,trylock() 會立刻 return,而 errno 為 EBUSY。

Unlock Mutex

1
pthread_mutex_unlock()

進入此 function 前,mutex 應為 locked 且被 calling thread 擁有。

fast mutex 會直接被 unlock。recursive mutex 需 call 相同於 lock 次數的 unlock 才會真正 unlock。

error check 跟 recursive 的 mutex 會檢查兩個條件:此 mutex 是否為 locked 且被 calling thread 擁有。若有一條件不符合,則不會 unlock,會 return error code。fast mutex 不會做此檢查,所以非擁有此 mutex 的 thread 也可以 unlock 它(這當然不好)。

Ref

  • Linux pthread_mutex man page
    • PS:Ubuntu 上要裝 glic-doc 才有 pthread 的 man page

為有「多型」性質(即有 virtual function)的 base class 宣告 virtual destructor。

C++ 沒有定義 base class 的 destructor 是 non-virtual 時以 base class pointer 刪除 derived class 的 object 的行為。常出現的結果是只有 base class 部分的 memory 會被釋放、derived class 部分的不會釋放,這會造成「局部銷毀」物件的問題,memory 當然就沒 free 乾淨。

用 virtual destructor 可以解決上述問題,因為 virtual function 的性質會 call 到 derived class 的 destructor。

不過不是把所有 base class 的 destructor 宣告成 virtual 就好,非必要(沒有 virtual function)時不需要這麼宣告。

Ref

  • 《Effective C++》

Old-style cast

C 風格的舊式轉型,在 C++ 裡不建議使用。

1
(T)expr

將 expr 轉成 type T。

C++-style cast

C++ 的新型轉型有四種:

1
const_cast<T>(expr)

將 const 轉成 non-const,只有這種轉型可以去掉 const。

1
dynamic_cast<T>(expr)

主要用來做 safe downcasting(將 base class pointer 轉成 derived class pointer),會在 runtime 判斷 object/expr 是否屬於 T 的繼承架構才進行轉型。轉型成功會傳回 address,失敗傳回 NULL。

因為要判斷 object 是否屬於繼承架構,dynamic_cast 是執行效率低、成本大的 casting。

1
reinterpret_cast<T>(expr)

少用。做低階轉型,例如將 int* 轉成 int。實際結果取決於 compiler,因此不可移植、無法跨平台。

1
static_cast<T>(expr)

強制轉型,就像舊式轉型,如將 non-const 轉為 const、int 轉為 double 等。也可以用來將 base class pointer 轉成 derived class pointer,但比較不安全。

Ref

C++ 對內建 type(如 int)要手動做 initial。

class member 的初始化

以 constructor 的 member initialization list 做 member 的初始化,會直接將參數丟給該 member 相對應的 constructor,可避免先 run member 的 default constructor 後才再做 assign,效率較好。

member 初始化順序:

  1. base class -> derived class
  2. 依宣告次序初始化(宣告次序與 member initialization list 的次序可能不同)

初始化 member 的原則:將所有 member 依照宣告順序列在 member initialization list 中。

non-local static object 的初始化

C++ 未定義在不同 translation unit((產生單一 object file 的 source code))中的 non-local static objects((不在 function 中的 static object,如 global object))的初始化相對次序。

這會造成一些問題,例如在 source code A 裡的 global object objA 的初始化會用到在 source code B 裡的 global object objB 時可能有問題,因為不知道 objA 是不是會比 objB 晚初始化。

解法:把 non-local static object 放到一 function 中,讓它不是 non-local,則可以知道初始化的順序。該 function return object 的 reference,要用這類 object 時就 call 相應 function。

Ref

  • 《Effective C++》p.27~28, 31

不可免俗的,Octopress 第一篇文章是 say hello。

在 Windows 上玩 Octopress + Github。

Prepare

要先裝好 Git 跟 Ruby 環境。Git 是用 Git for Windows,Ruby 環境則從從 http://rubyinstaller.org/downloads 下載 RubyInstaller 1.9.3 跟 Development kit 來安裝。

Development kit 下載後先解壓縮,用以下指令安裝:

1
2
3
$ cd <DEVKIT_INSTALL_DIR>
$ ruby dk.rb init
$ ruby dk.rb install

安裝完 Ruby 要在環境變數 PATH 加入 Ruby 的 bin 資料夾路徑,如 C:\Ruby193\bin

Install Octopress

我直接用 Git Bash 下指令。

1
2
3
4
5
6
$ git clone git://github.com/imathis/octopress.git octopress
$ gem update --system
$ gem install bundler
$ cd octopress
$ bundle install
$ rake install

Configuration

編輯 _config.yml 可修改 blog 的主要設定。

Read more »