C++ でマルチスレッドデザインパターン

C++03 では言語仕様として thread 機能が定義されておらず、プラットフォーム非依存のスレッド関係のコードを書こうとした場合 Boost.Thread などのライブラリを使うしかなかったのですが、ご存知の通り C++11 から thread 関係の機能が標準ライブラリに取り込まれたためより手軽にスレッドの機能が利用できるようになりました (といいつつ、完全にサポートしている処理系はまだないようですが…)

そこで結城浩氏の 「Java言語で学ぶデザインパターン入門 マルチスレッド編 (原著 Concurrent Programming in Java 他)」で紹介されているパターンを C++ でやったらどうなるか紹介してみたいと思います。

※リンクが無いところはまだ記事書いてないです。すみません…

C++er 向け、 C++ の型判定エクササイズ (1)

一般的な入門書には殆んど載っていない(と思われる) C++ の型にまつわる問題を少し…

EX.1  以下の typedef された t0 ~ t12 の型は一体何になるでしょうか。

typedef int t0;
typedef int* t1;
typedef int t2(int);
typedef int(t3)(int);
typedef int(*t4)(int);
typedef int(&t5)(int);
typedef int t6[3];
typedef int (t7)[3];
typedef int(*t8)[3];
typedef int(&t9)[3];
typedef int(&(*t10)(int))[3];
typedef int(*(&t11)(int))[3];
typedef int(*(&t12)(int))(int);
typedef int(Foo::*t13)(int);

— 答え —
t0: int型
t1: intへのポインタ型
t2: intを1つ引数にとり、戻り値がintの関数型
t3: t2 と同じ
t4: intを1つ引数にとり、戻り値がintの関数へのポインタ型
t5: intを1つ引数にとり、戻り値がintの関数の参照型
t6: 3つのintを要素に持つ配列型
t7: t6 と同じ
t8: 3つのintを要素に持つ配列へのポインタ型
t9: 3つのintを要素に持つ配列の参照型
t10: intを1つ引数にとり、戻り値が「3つのintを要素に持つ配列への参照」の関数へのポインタ型
t11: intを1つ引数にとり、戻り値が「3つのintを要素に持つ配列へのポインタ」の関数の参照型
t12: int を一つ引数にとり、戻り値が「intを1つ引数にとり、戻り値がintの関数へのポインタ」の関数の参照型
t13: intを1つ引数にとり、intを返すFooのメンバー関数へのポインタ型

EX.2  以下の new を含んだ式はそれぞれ何をしているでしょうか。

new int[3]
(new int)[3]
new (int [3])
new (int (*[3])())
new (int(*)[3])
new (int(*[3])[3])

— 答え —
new int[3] : int 型3つ分の領域を new
(new int)[3] : new した int 型の領域から offset 3 の場所に(不正)アクセス
new (int [3]) : int 型3つ分の領域を new
new (int (*[3])()) : 引数無しで int を返却する関数ポインタ型3つ分の領域を new
new (int(*)[3]) : 3つのintを要素に持つ配列型へのポインタを new
new (int(*[3])[3]) : 3つのintを要素に持つ配列型へのポインタ3つ分の領域を new

EX.1 の使用例
EX.2 の使用例(まだ書いてません…)

どうでしょう? 全部楽勝で答えられたアナタは多分中級者以上 !

Intel NUC NUC5i3RYH に Linux Mint を入れてみた

自宅で使用している NAS が今まさに天寿を全うしようとしておりまして、samba を入れてファイルサーバーにしつつ、ついでに少し遊べればいいかなと言う算段で購入。

開封直後

IMG_0221

アダプターは先が取り替え可能になっていて、いろんな国の仕様に対応しているようです。

IMG_0230

裏蓋を開けた所

IMG_0222

メモリーを刺した所

IMG_0224

SSD を刺した所

IMG_0226

これで蓋を閉めればハードの準備は完了!後は UNetbootin を使って ISO から live usb メモリーを作成してインストールします。

unetbootin

Intel NUC の前モデルでは Linux のインストールにハマったと言う記事がちらほらありましたので、自分もハマるだろうな…

と思っていたら意外と何の問題もなくあっさり Linux Mint が入りました。これから存分に活躍して貰う予定です。

 

C++ で Single Thread Execution パターン

複数のスレッドから同時に実行されると問題になるような箇所はなんらかの形で排他制御を行い、ひとつのスレッドからしか実行されないようにしなければなりません。

「Single Thread Execution パターン」は簡単に言えば「排他が必要な箇所は排他制御をきちんとしましょうね」というパターンです。(マルチスレッドプログラミングにおける大変基本的な内容なので仰々しくパターンと呼ぶほどでもないような気が個人的にはしますが… 基本こそ大事と言うことでしょう)

C++ の標準ライブラリで排他制御を行うには std::mutex を使用します。以下は、良くある 2つのスレッドから同じ int 型の変数をインクリメントする例です。

lambda 式 f がスレッドで実行される処理の本体で、中では参照渡しされた int 型の変数 count を100万回インクリメントしています。

きちんと排他が行われている場合、上記の例では join 後の最終的な count の値は 200万になりますが、排他されていない場合はほとんどのケースで200万より小さな値になるはずです。

上記のようなただ単に変数をインクリメントするようなケースでは std::mutex  よりも以下のように std::atomic を利用した方がパフォーマンスの点で有利ですのであまり実践的なコードとは言えませんがあくまで例として。

ちなみにインクリメント結果が200万より小さくなる理由、std::atomic  の方がパフォーマンスがよくなる理由は CPU の命令セットや C++ 処理系の動作などに関係があるのですが、本題から逸れますし長くなりますのでまた別の機会に…

C++ でマルチスレッドデザインパターン

C++11 の std::function を使って signal-slot ライクにメンバー関数をコールバック

この記事の補足。 std::function を使って Qt の signal-slot みたくメンバー関数をコールバックする方法あれこれ。

例によって擬似タイマー

(1) 関数スコープ内で定義したラムダ式を connect

(2) メンバー変数定義したラムダ式を connect

(3) std::bind で this ポインターを bind して connect

(4) メンバー関数 –> std::function アダプターを自作

(1)~(4) は全部こんな感じで使用可能

他にもまだやり方があるかもしれませんが、とりあえず思いつくだけ。