0%

這種檔案格式最近才流行起來,7zup可以直接解壓縮。
在Linux底下可以這麼作

1
2
$ xz *.tar.xz
$ tar xvf *.tar

chrono原先是來自於boost,現在進入C++11 Standard了。
鑽簡單的範例就是用來作高精密度的Timer使用。原先在Windows有QueryPerformanceCounter的函數,可以精密到nanoseconds,在Liunx/BSD很難找到類似的解法,不過C++11把這納入標準了,不必花太多功夫。
以下是一個範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;
void f()
{
this_thread::sleep_for(chrono::seconds(1));
}

int main()
{
auto t1 = chrono::high_resolution_clock::now();
f();
auto t2 = chrono::high_resolution_clock::now();
std::cout << "f() took "
<< chrono::duration_cast<chrono::seconds>(t2 - t1).count()
<< " seconds\n"
<< chrono::duration_cast<chrono::milliseconds>(t2 - t1).count()
<< " milliseconds\n"
<< chrono::duration_cast<chrono::nanoseconds>(t2 - t1).count()
<< " nanoseconds\n";
return 0;
}

更多的使用方法可以參考

最近遇到在GitHub frok出來的Branch改爛之後,想要捨棄掉自己的修改,重新跟上Upstream的狀態。
沒想到已經有人解答了
Clean up a fork and restart it from the upstream
GitHub page, section “What should I do if I’m in a bad situation”
就是以下四個指令的組合技

1
2
3
4
$ git fetch upstream
$ git checkout master
$ git reset --hard upstream/master
$ git push origin master --force

寫一下編譯跟安裝Boost該注意的事,目前先寫Linux下的情況,有時間日後再補上

Linux (Ubuntu 13.04)

1
2
3
$ apt-get install g++ g++-4.8 g++-4.8-multilib gcc-4.8-doc libstdc++6-4.8-dbg libstdc++-4.8-doc
$ cd boost_1_55_0
$ ./bootstrap.sh ## Generate bjam

關於bootstrap.sh的詳細用法可以打./boostrap.sh --help獲得,。如果不更改--prefix的話,預設的路徑就是/usr/local

1
$ ./bjam --build-dir=./tmp --stagedir=./build

關於bjam的常用使用說明可以參照,以下是常用參數

  • –build-dir=directory 將build過程的中間產物放置目錄底下,方便管理
  • –stagedir=directory 最後編譯完成的Library放置處
  • –variant=debug | release 可以選擇Release 或是 Debug模式
  • –link=static | shared 選擇build出來的事static library或是sshared library
  • –threading=single | multi 選擇Threading model
  • –runtime-link=static | shared 連結C/C++ Standard Library時,選擇Static library或是Shared library link
  • –with- 只編譯某Library,如 --with-regex
    ` –clean 清理中間產物
    編譯玩之後就可以安裝了
    1
    $ ./bjam install

在Stackoverflow看到,怕忘記寫下來。

如何對std::map使用 for-ranged syntax

原文在此。
簡單的說就是用auto去接reference。

1
2
3
for (auto& kv : myMap) { 
std::cout << kv.first << " has value " << kv.second << std::endl;
}

如何反向訪問container

原文在此。
最簡單的方法是使用Boost

1
2
3
4
#include <boost/range/adaptor/reversed.hpp>

for (auto i : boost::adaptors::reverse(x))
std::cout << i << '\n';

如果沒有boost的話也可以土法煉鋼,原文Paul的方法不能使用,選用下面Jive的方案

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
template<class Fwd>
struct Reverser_generic {
Fwd &fwd;
Reverser_generic(Fwd& fwd_) : fwd(fwd_) {}
typedef std::reverse_iterator<typename Fwd::iterator> reverse_iterator;
reverse_iterator begin() { return reverse_iterator(std::end(fwd)); }
reverse_iterator end() { return reverse_iterator(std::begin(fwd)); }
};

template<class Fwd >
struct Reverser_special{
Fwd &fwd;
Reverser_special(Fwd& fwd_) : fwd(fwd_) {}
auto begin() -> decltype(fwd.rbegin()){ return fwd.rbegin(); }
auto end() ->decltype(fwd.rbegin()) { return fwd.rend(); }
};

template<class Fwd>
auto reverse_impl(Fwd& fwd, long) -> decltype(Reverser_generic<Fwd>(fwd)){
return Reverser_generic<Fwd>(fwd);
}

template<class Fwd>
auto reverse_impl(Fwd& fwd, int)
-> decltype(fwd.rbegin(), Reverser_special<Fwd>(fwd))
{
return Reverser_special<Fwd>(fwd);
}

template<class Fwd>
auto reverse(Fwd&& fwd) -> decltype(reverse_impl(fwd, int(0))) {
static_assert(!(is_rvalue_reference<Fwd&&>::value),
"Cannot pass rvalue_reference to dj::reverse()");
return reverse_impl(fwd, int(0));
}

相信大家都有用過grep來找文字,不過這個ack是專為程式設計師開發的。
從官網下載並安裝

1
2
3
$ curl http://beyondgrep.com/ack-2.12-single-file > ack
$ sudo mv ack /usr/local/bin
$ sudo chmod 755 /usr/local/bin/ack

ack有以下這些特性

  • 預設就搜尋當前目錄
  • 預設搜尋所有子目錄
  • 忽略Metadata資料節,如.svn.git
  • 忽略Binary檔
  • 印出找到Pattern的行號
  • 能夠搜尋特定文件類型的檔案 (如Perl/C++)
  • Highlight搜尋結果
  • 支持Perl的Advance Regular Expression

幾個常用的功能

如何只搜尋eat而忽略掉feature和`eating

1
$ ack -w eat 

當Pattern中有特殊字元的時候,需要當作Literal chracter被匹配

1
$ ack -Q '$path/$'

放棄搜尋某些目錄

1
$ ack about --ignore-dir=downloads 

列出某些特定文件類型的檔案,列出擁有Pattern的檔案名稱

以Makefile為例,可能的檔名有 *.mk, makefile, Makefile
我們想知道這些檔案裡面哪些定義了CFLAGS,就能夠這樣作

1
$ ack --make -l CFLAG 

Highlight某些特定Pattern

1
$ tail -f /var/log/syslog | ack --passthru 192.168.1.10 

這裡的passthru是不管有沒有匹配到都會輸出。

Update

在網路上釉看到ag這套軟體。用途大同小異。多了一些ack沒有的功能。
可以參考Conquering the Command Line Chapter 2. Ack/Ag

既然git是個自由度很高的version control system,對於該怎麼工作這件事,也沒有什麼固定答案,除了當SVN那樣子用法之外,還有其他答案,因此就有這篇文章的產生。

Simple Git Workflow

重點只有三個

  • 當要開發New features時,就開一個New feature的Branch,且在上面開發
  • 將New feature的Code合併回master
  • 另外準備一個Branch,用作Deploy/Release用,在這邊發布的Code要經過Well test過的

A successful Git branching model

這是上面那種方式的無敵加強版

  • Mainstream從master移到了develop,master只維持穩定的版本。
  • feature分支一樣是開發New feature,完成之後會合併至develop
  • Release branches: 準備要 release 的版本,只修 bugs。從 develop 分支出來,完成後 merge 回 master 和 develop
  • Hotfix branches: 等不及 release 版本就必須馬上修 master 趕上線的情況。會從 master 分支出來,完成後 merge 回 master 和 develop
    這套流程固然強大,不過太複雜了。
    git-flow可以幫助簡化一些情況。
    可以參考Git flow 開發流程

Github flow

有鑑於上面那種方式太複雜,又衍生出來的新方式,也是GitHub自己在用的工作流程。感覺很像第一種方式,不過加上了Code review的能力。

Helgrind 和 DRD

這兩個工具都是Valgrind的一部分,用途也相同,檢查Thread error,不過用的策略不同,可以交替使用檢茶室否有無隱藏的錯誤。
以下是從Binary hacks抄下的範例

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
#include <pthread.h>
static int count = 1;
void *incr_count(void *p) {
count++;
return 0;
}
static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;
void *lock_m1_then_m2(void *p) {
pthread_mutex_lock(&m1);
pthread_mutex_lock(&m2);
pthread_mutex_unlock(&m2);
pthread_mutex_unlock(&m1);
return 0;
}
void *lock_m2_then_m1(void *p) {
pthread_mutex_lock(&m2);
pthread_mutex_lock(&m1);
pthread_mutex_unlock(&m1);
pthread_mutex_unlock(&m2);
return 0;
}
int main() {
pthread_t t1, t2, t3, t4;
pthread_create(&t1, NULL, incr_count, NULL);
pthread_create(&t2, NULL, incr_count, NULL);
pthread_create(&t3, NULL, lock_m1_then_m2, NULL);
pthread_create(&t4, NULL, lock_m2_then_m1, NULL);
pthread_join(t4, NULL);
pthread_join(t3, NULL);
pthread_join(t2, NULL);
pthread_join(t1, NULL);
return count;
}

裡面有兩個錯誤,一個是count在multi-thread的情況沒有保護,這種情況也可以用下面的thread-sanitizer偵測出來。
另外一種情況就是lock的順序不同,導致Deadlock的情景。
編譯且執行

1
2
$ gcc demo.c -o demo -lpthread
$ valgrind --tool=drd ./demo

輸出太長,列出感興趣的部份

==5172== Possible data race during write of size 4 at 0x600C90 by thread #3
==5172== Locks held: none
==5172== at 0x40065F: incr_count (in /home/hungming/a)
==5172== by 0x4C2DB38: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5172== by 0x4E3BE99: start_thread (pthread_create.c:308)
==5172==
==5172== This conflicts with a previous write of size 4 by thread #2
==5172== Locks held: none
==5172== at 0x40065F: incr_count (in /home/hungming/a)
==5172== by 0x4C2DB38: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5172== by 0x4E3BE99: start_thread (pthread_create.c:308)

上面這編列出可能有data-race的情形。

==5172== Thread #5: lock order “0x600CA0 before 0x600CC8” violated
==5172==
==5172== Observed (incorrect) order is: acquisition of lock at 0x600CC8
==5172== at 0x4C2DFCD: pthread_mutex_lock (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5172== by 0x4006FB: lock_m2_then_m1 (in /home/hungming/a)
==5172== by 0x4C2DB38: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5172== by 0x4E3BE99: start_thread (pthread_create.c:308)
==5172==
==5172== followed by a later acquisition of lock at 0x600CA0
==5172== at 0x4C2DFCD: pthread_mutex_lock (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5172== by 0x40070B: lock_m2_then_m1 (in /home/hungming/a)
==5172== by 0x4C2DB38: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5172== by 0x4E3BE99: start_thread (pthread_create.c:308)

這邊告訴我們lock的順序不對。
更多的使用方法可以參考
Helgrind使用說明
DRD使用說明

thread-sanitizer

thread-sanitizer現在已經是LLVM的一部分,在編譯LLVM的時候就會編譯完成,而GCC 4.8之後也支援thread-sanitizer。
這跟上面的不同是檢查data-race issue。
寫個sample code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <pthread.h>
int Global;
void* Thread1(void* x) {
Global++;
return NULL;
}

void* Thread2(void* x) {
Global--;
return NULL;
}

int main() {
pthread_t t[2];
pthread_create(&t[0], NULL, Thread1, NULL);
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
return 0;
}

這個範例很簡單,可以看出 Global 在不同Thread下操作可能出現問題。
編譯且執行,注意要加上-fsanitize=thread

1
2
$ clang simple_race.c -fsanitize=thread -g
$ ./a.out

同樣列出我們所關心的部份

WARNING: ThreadSanitizer: data race (pid=4441)
Location is global ‘Global’ of size 4 at 0x7f4d31e90ad8 (a+0x0000016caad8)
SUMMARY: ThreadSanitizer: data race ??:0 Thread2

有了Tool之後,從Log分西問題出在哪就便得很重要了。