0%

Visual C++ 2015提供了一個Coroutine的實驗性實作,未來可能會被列入C++17當中,因此先來體驗一下

Generator

這寫法就跟Python差不多了,直接用yield就行了
不過跟Javascript的Generator還是有一定程度的不同

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
#include <iostream>
#include <experimental/generator>
using namespace std::experimental;
using namespace std;

generator<int> fib()
{
int a = 0;
int b = 1;
for (;;) {
yield a;
auto next = a + b;
a = b;
b = next;
}
}

int main(int argc, char* argv[])
{
for (auto v : fib()) {
if (v > 50)
break;
cout << v << endl;
}
}

async function

以下是個示範程式

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
#include <future>
#include <iostream>
using namespace std;
using namespace std::chrono;

// this could be some long running computation or I/O
future<int> calculate_the_answer()
{
return async([] {
this_thread::sleep_for(1s); return 42;
});
}

// Here is a resumable function
future<void> coro() {
cout << this_thread::get_id() << " Started waiting... \n";
auto result = await calculate_the_answer();
cout << this_thread::get_id() << " : woke up, get " << result << endl;
}

int main(int argc, char* argv[])
{
coro().get();
cout << this_thread::get_id() << ": back in main\n";
}

future<void>await的語法實在是有點突兀(尤其是其他語言都用asyncawait之後)
如果我們拿掉await會造成怎樣的結果

1
2
3
4
5
6
7
8
9
10
11
void noncoro() {
cout << this_thread::get_id() << " Started waiting... \n";
auto result = calculate_the_answer().get();
cout << this_thread::get_id() << " : woke up, get " << result << endl;
}

int main(int argc, char* argv[])
{
noncoro();
cout << this_thread::get_id() << ": back in main\n";
}

可以看到兩個函數的不同

  • coro: Main Thread Invoke calculate_the_answer -> Child Thread Return
  • noncoro: Main Thread Invoke calculate_the_answer -> Main Thread Return

Complex Example

這個範例有點複雜,有時間在研究吧

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
#include <windows.h>
#include <future>
#include <iostream>
#include <experimental/resumable>
using namespace std;
using namespace std::chrono;
using namespace std::experimental;

auto operator await(system_clock::duration duration) {
class awaiter {
static void CALLBACK TimerCallback(PTP_CALLBACK_INSTANCE, void *Context, PTP_TIMER) {
coroutine_handle<>::from_address(Context)();
}
PTP_TIMER timer = nullptr;
system_clock::duration duration;
public:
explicit awaiter(system_clock::duration d) : duration(d) {}
bool await_ready() const { return duration.count() <= 0; }
bool await_suspend(coroutine_handle<> resume_cb) {
int64_t relative_count = -duration.count();
timer = CreateThreadpoolTimer(TimerCallback, resume_cb.to_address(), nullptr);
SetThreadpoolTimer(timer, (PFILETIME)&relative_count, 0, 0);
return timer != 0;
}
void await_resume() {}
~awaiter() { if (timer) CloseThreadpoolTimer(timer); }
};
return awaiter{ duration };
}

future<void> test() {
cout << this_thread::get_id() << ": sleeping...\n";
await 1s;
cout << this_thread::get_id() << ": woke up\n";
}

int main() {
test().get();
cout << this_thread::get_id() << ": back in main\n";
}

Reference

Resumable functions in C++
Coroutines in Visual Studio 2015 - Update 1
Stackless coroutines with Visual Studio 2015

1
2
3
4
5
6
7
8
template <typename T>
struct has_member_foo
{
template <typename U, void (U::*)()> struct SFINAE {};
template <typename U> static char check(SFINAE<U, &U::foo>*);
template <typename U> static int check(...);
static const bool value = sizeof(check<T>(0)) == sizeof(char);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <utility>
template <typename T>
struct has_member_foo11
{
private:
template<typename U> static auto check(int) ->
decltype(std::declval<U>().foo(), std::true_type());

template<typename U> static std::false_type check(...);

public:
enum {
value = std::is_same<decltype(check<T>(0)),std::true_type>::value
};
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <typename T, typename ...Args>
struct has_member_foo11
{
private:
template<typename U> static auto check(int) ->
decltype(std::declval<U>().foo(std::declval<Args>()...), std::true_type());

template<typename U> static std::false_type check(...);

public:
enum {
value = std::is_same<decltype(check<T>(0)),std::true_type>::value
};
};

由於Ubuntu自帶的NodeJS版本實在太舊了,只好自行安裝,動手跑一遍流程,記錄下來。目前的NodeJS還無法完全支援ES6,所以還需要Babel之類的轉成ES5執行。

使用NVM安裝NodeJS

1
2
$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.29.0/install.sh | bash
$ nvm install stable

安裝Babel

1
$ npm i -g babel-cli

First Project

1
2
3
$ mkdir test && cd test
$ npm init
$ vim test.js

以下是測試程式,用到了ES6的let和ES7的asyncawait等Feature。

1
2
3
4
5
6
7
8
9
10
11
12
function sleep(ms = 0) {
return new Promise((resolve, reject) => setTimeout(resolve, ms));
}

async function test() {
for (let i = 0; i < 10; i++) {
await sleep(500);
console.log(`i = ${i}`);
}
}

test().then(() => console.log('done'));

執行的時候遇到困難

1
2
3
4
5
6
7
8
9
$ babel-node test.js
SyntaxError: /test/test.js: Unexpected token (5:6)
3 | }
4 |
> 5 | async function test() {
| ^
6 | for (let i = 0; i < 10; i++) {
7 | await sleep(500);
8 | console.log(`i = ${i}`);

因為Babel沒辦法正確的轉譯ES7語法

Problem Solving

1
$ npm i babel-preset-es2015 babel-preset-stage-0 --save-dev

在目前目錄上新增.babelrc`

1
2
3
{
"presets": ["es2015", "stage-0"]
}

這樣程式就能漲常執行。

Compile to ES5

當然,可能還有跑在Browser的需求,因此轉成ES5還是必須的。

1
2
3
4
5
6
7
8
9
10
11
12
$ babel test.js --out-file test.compiled.js
$ node test.compiled.js
/test/test.compiled.js:14
var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {

ReferenceError: regeneratorRuntime is not defined
at /test/test.compiled.js:14:31
``
還是遇到問題。
#### Problem Solving
~~~bash
$ npm i babel-polyfill --save-dev

在est.compile.js爭最前面加上

1
require("babel-polyfill");
1
$ node  test.compiled.js

這下正常了

Problem

夜路走多了總是會碰到鬼,講述一下遇到的情形
我們有兩個Shared library,liba.solibb.so
內容類似如此

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
void inner()
{
printf("inner in a\n");
}
void outer_a()
{
printf("outer in a\n");
inner();
}

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
void inner()
{
printf("inner in b\n");
}
void outer_b()
{
printf("outer in b\n");
inner();
}

如果有個程式這樣寫

1
2
3
4
5
6
7
void outer_a();
void outer_b();
int main()
{
outer_a();
outer_b();
}

當我們編譯這個程式

1
2
$ gcc main.c liba.so libb.so -o main
$ LD_LIBRARY_PATH=./ ./main

結果匯出呼常理預料之外ㄝ,取決於Linking順序,跟我們想要的結果不同。

Simple Solution

將其中一個inner function加上static即可。如

1
2
3
4
static void inner()
{
printf("inner in b\n");
}

這樣結果就可以正常運作了,不過不適用於C++ Member Function之類的,我遇到的情形不是用這種寫法。

Best Solution (Hidden Visibility)

跟上面的方法類似,只需要將其中之一的inner隱藏寢來不可見就行了,將需要的Function輸出

1
2
3
4
5
6
7
8
9
10
11
#define EXPORTED __attribute__((visibility("default")))
#include <stdio.h>
void inner()
{
printf("inner in b\n");
}
EXPORTED void outer_b()
{
printf("outer in b\n");
inner();
}

編譯的時候就選擇

1
$ gcc -fPIC -shared -fvisibility=hidden b.c -o libb.so

就可以達成想要的結果了

Reference

how to link with two shared libraries with many conflicting functions

我只是個Javascript初新者,寫出來的可能也會務人子弟。
只是對Javascript的Asynchronous Programming Model有興趣,紀錄一下。

Callback Hell

在最初的Javascript的設計,程式只能這樣寫。一層又一層的Callback。不蛋難以維護,並且容易出錯。

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
function wait(func, val) {
return setTimeout(() => {
func(val);
}, 1000);
}
function asyncTask() {
var val = 0;
wait((val) => {
console.log("Step 1");
console.log(val);
wait((val) => {
console.log("Step 2");
console.log(val);
wait((val) => {
console.log("Step 3");
console.log(val);
wait((val) => {
console.log("Finish");
console.log(val);
}, val + 4);
}, val + 3);
}, val + 2);
}, val + 1);
}

asyncTask();

ES6之後引季Promise,可以將Callback從水平拓展變成垂直拓展,讓程式碼更像是一般Synchronous Programming的方式

Promise

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
function wait(func, val) {
return setTimeout(() => {
func(val);
}, 1000);
}
function finish(val) {
console.log("Finish");
console.log(val);
}
function step3(val) {
console.log("Step 3");
console.log(val);
}
function step2(val) {
console.log("Step 2");
console.log(val);
}
function step1(val) {
console.log("Step 1");
console.log(val);
}
function waitPromise(func, val) {
return new Promise((resolve, reject) => {
wait(() => {
func(val);
resolve(val);
});
});
}
function asyncTask() {
var val = 0;
return waitPromise(step1, val + 1).then((val) => {
return waitPromise(step2, val + 2);
}).then((val) => {
return waitPromise(step3, val + 3);
}).then((val) => {
return waitPromise(finish, val + 4);
});
}

asyncTask();


asyncTask();

Generator

不過ES6同樣引入了Generator,可以用Generator模擬Synchronous Programming的方式
asyncTaskFlow是個Generator就是控制流,只是我們要以這個順序執行
比起Promise更像是我們熟悉的方式

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
function wait(func) {
return setTimeout(func, 1000);
}
function finish() {
console.log("Finish");
}
function step3() {
console.log("Step 3");
}
function step2() {
console.log("Step 2");
}
function step1() {
console.log("Step 1");
}
function* asyncTaskFlow() {
yield wait(step1);
yield wait(step2);
yield wait(step3);
yield wait(finish);
}
function asyncTask() {
var gen = asyncTaskFlow();
for (v of gen) ;
}

asyncTask();

Async & Await

跟C#一樣,用Async和Awit作為最終解決方案,雖然這還處在ES7 Draft,不過日後應該會被採用
可以參考 ES7 async functionsSimplifying Asynchronous Coding with ES7 Async Functions

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
async function finish(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Finish");
resolve(val + 4);
});
});
}
async function step3(val ) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 3");
resolve(val + 3);
});
});
}
async function step2(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 2");
resolve(val + 2);
});
});
}
async function step1(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 1");
resolve(val + 1);
});
});
}
async function asyncTask() {
var result = await step1(0);;
console.log(result);
result = await step2(result);
console.log(result);
result = await step3(result);
console.log(result);
result = await finish(result);
console.log(result);
}
asyncTask();
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
function wait(func) {
return setTimeout(func, 1000);
}
async function finish(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Finish");
resolve(val + 4);
});
});
}
async function step3(val ) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 3 failed");
reject("Cancel operation");
});
});
}
async function step2(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 2");
resolve(val + 2);
});
});
}
async function step1(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 1");
resolve(val + 1);
});
});
}
async function asyncTask() {
try {
var result = await step1(0);;
console.log(result);
result = await step2(result);
console.log(result);
result = await step3(result);
console.log(result);
result = await finish(result);
console.log(result);
} catch (err) {
console.log(err);
}
}
asyncTask();

有時候想要在Linux的Terminal想要印出彩色字串方便,可以有以下方法

C Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#define ANSI_COLOR_RED "\x1b[31m"
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_YELLOW "\x1b[33m"
#define ANSI_COLOR_BLUE "\x1b[34m"
#define ANSI_COLOR_MAGENTA "\x1b[35m"
#define ANSI_COLOR_CYAN "\x1b[36m"
#define ANSI_COLOR_RESET "\x1b[0m"
};

int main (int argc, char const *argv[]) {

printf(ANSI_COLOR_RED "This text is RED!" ANSI_COLOR_RESET "\n");
printf(ANSI_COLOR_GREEN "This text is GREEN!" ANSI_COLOR_RESET "\n");
printf(ANSI_COLOR_YELLOW "This text is YELLOW!" ANSI_COLOR_RESET "\n");
printf(ANSI_COLOR_BLUE "This text is BLUE!" ANSI_COLOR_RESET "\n");
printf(ANSI_COLOR_MAGENTA "This text is MAGENTA!" ANSI_COLOR_RESET "\n");
printf(ANSI_COLOR_CYAN "This text is CYAN!" ANSI_COLOR_RESET "\n");
return 0;
}

這方法簡單,不過麻煩的是要手動加上Color跟Reset標籤在文字前後。

C++11 Solution

突然想到可以用C++11的新特性User defined literal來簡化,可以減少不少手動置入的風險。也可以練習User defined literal的如何使用。

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
#include <stdio.h>
#include <string>
namespace {
#define ANSI_COLOR_RED "\x1b[31m"
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_YELLOW "\x1b[33m"
#define ANSI_COLOR_BLUE "\x1b[34m"
#define ANSI_COLOR_MAGENTA "\x1b[35m"
#define ANSI_COLOR_CYAN "\x1b[36m"
#define ANSI_COLOR_RESET "\x1b[0m"


#define DEFINE_COLOR_STRING(color) \
std::string operator"" _##color (const char* str) \
{ \
std::string tmp(ANSI_COLOR_##color); \
tmp += str; \
tmp += ANSI_COLOR_RESET; \
return tmp;\
}
DEFINE_COLOR_STRING(RED);
DEFINE_COLOR_STRING(GREEN);
DEFINE_COLOR_STRING(YELLOW);
DEFINE_COLOR_STRING(BLUE);
DEFINE_COLOR_STRING(MAGENTA);
DEFINE_COLOR_STRING(CYAN);
};
std::cout << 123_RED << 456_YELLOW << 789_BLUE << std::endl;

不過User Defined Literal前的字串似乎不能寫成”123 456”_RED這種形式。有點可惜

```

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename T, std::size_t N>
class ArrayResult {
constexpr static std::size_t size_ = N;
T data_[N] {};
public:
constexpr std::size_t size() const { return N; }
constexpr T& operator[](std::size_t n) { return data_[n]; }
constexpr const T& operator[](std::size_t n) const { return data_[n]; }
using iterator = T*;
using const_iterator = const T*;
constexpr iterator begin() { return &data_[0]; }
constexpr const_iterator begin() const { return &data_[0]; }
constexpr iterator end() { return &data_[N]; }
constexpr const_iterator end() const { return &data_[N]; }
};

好久沒寫文章了,把之前看到的資料記一記。馬有失蹄,人有錯手,在怎麼宣告不用Debugger的Programming language,可能也需要gdb搭配使用,這邊紀錄一下如何用gdb來幫助golan除錯。
範例程式

1
2
3
4
5
6
7
8
9
10
11
12
package main

import (
"fmt"
)

func main() {
for i := 0; i < 5; i++ {
fmt.Println("Loop")
}
fmt.Println("Done")
}

編譯時間入debuu info

1
$ go build -gcflags "-N -l" test.go

積著就可以照

1
2
$ gdb test
$ b main.main

之後就能夠像之前一樣使用gdb了

Reference

Debugging Go Code with GDB
– [Debugging Go (golang) programs with gdb ]http://thornydev.blogspot.tw/2014/01/debugging-go-golang-programs-with-gdb.html)
Introduction to Go Debugging with GDB
Using the gdb debugger with Go

Macro這東西很早就有了,不過各有巧妙不同。
在Assembler的年代就已經有Macro了

1
2
3
4
COPY            macro   Dest, Source
mov ax, Source
mov Dest, ax
endm

而在C語言的時候,Macro的被使用了更頻繁了

1
#define min(a, b) ((a < b) ? a : b)

C語言的Macro也很簡單,就只是作文字的代換而已。Side Effect除外,出錯的話也很難Debug,因此其他語言打算因此作改進。

Define group of functions

1
2
3
4
5
6
7
8
9
10
11
12
13
#define CK_PR_FENCE(T, I)                               \
CK_CC_INLINE static void \
ck_pr_fence_strict_##T(void) \
{ \
__asm__ __volatile__(I ::: "memory"); \
}

CK_PR_FENCE(atomic, "sfence")
CK_PR_FENCE(atomic_store, "sfence")
CK_PR_FENCE(atomic_load, "mfence")
CK_PR_FENCE(store_atomic, "sfence")
CK_PR_FENCE(load_atomic, "mfence")
CK_PR_FENCE(load, "lfence")

在這情況下 Templateˊ無能為力.

Rust

Macro overload

1
2
3
4
5
6
7
8
9
10
11
12
13
macro_rules! sayHello {
() => {
println!("sayHello");
};
($name:ident) => {
println!("sayHello {:?}", stringify!($name));
};
}
fn main() {
sayHello!();
sayHello!(ABC);

}

Pattern Matching

1
2
3
4
5
6
7
8
9
macro_rules! min {
// base case
($x:expr) => ($x);
// `$x` followed by at least one `$y,`
($x:expr, $($y:expr),+) => (
// call min! on the tail `$y`
std::cmp::min($x, min!($($y),+))
)
}

Recursive Macro

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
macro_rules! write_html {
($w:expr, ) => (());

($w:expr, $e:tt) => (write!($w, "{}", $e));

($w:expr, $tag:ident [ $($inner:tt)* ] $($rest:tt)*) => {{
write!($w, "<{}>", stringify!($tag));
write_html!($w, $($inner)*);
write!($w, "</{}>", stringify!($tag));
write_html!($w, $($rest)*);
}};
}

fn main() {
use std::fmt::Write;
let mut out = String::new();

write_html!(&mut out,
html[
head[title["Macros guide"]]
body[h1["Macros are the best!"]]
]);

assert_eq!(out,
"<html><head><title>Macros guide</title></head>\
<body><h1>Macros are the best!</h1></body></html>");
}

Nim

Reference

Macros - Rust Documentation
A Quick Intro to Rust Macros
Module macros - Nim
Nim Manual

雖然這些東西網路上都找得到,不過為了節省時間,把相關步驟一次記下來。

UsersFetchingSource

有些時刻/usr/src是空的,所以需要手動獲取程式碼

1
2
$ pkg install svnup
$ svnup stable -h svn.freebsd.org

The Configuration File

修改自己需要的Configuration File

1
2
$ cd /usr/src/sys/amd64/conf
$ cp GENERIC MYKERNEL

Building and Installing a Custom Kernel

1
2
3
$ cd /usr/src
$ make buildkernel KERNCONF=MYKERNEL
$ make installkernel KERNCONF=MYKERNEL

Reference: