#pragma twice

KAB-studio > プログラミング > #pragma twice > 268 Version 14.01 マルチスレッドって?

#pragma twice 268 Version 14.01 マルチスレッドって?

前のページへ 表紙・目次へ 次のページへ

 Version 14.01
マルチスレッドって?

さて、今回からは、いわゆる【マルチスレッド】について説明していきま

マルチスレッドってよく聞くよねー
もう今では使いこなせないと困る機能のひとつになっているからね。でも
プログラムとして組むときには実はものすごく気を付けて使わなきゃいけな
い機能でもあるんです
そんなに気を付けなきゃいけないの?
そう、特にバグが出ても原因がわかりにいくのが一番の難点
げげげ
今回もそういった細かい所に触れつつ進めていくからねー
はーい
さて、まずは全体の概要について説明します。【マルチスレッド】は、プ
ログラムの〈流れ〉を増やすことを指します
プログラムの流れ?
たとえば

void OutputTest( int p_i )
{
    TRACE( "p_i = %d\n", p_i );
    p_i += 200;
    TRACE( "p_i = %d\n", p_i );
}

という関数を呼び出す場合を考えます。普通に2度呼ぶ場合には

void Use_OutputTest()
{
    OutputTest( 100 );  // ←A
    OutputTest( 200 );  // ←B
}

という感じになります
当然よねー
このとき、必ずAの呼び出しが終わってから、Bの呼び出しが行われま

当然よねー……それがなんないのがマルチスレッドってこと?
そういうこと。マルチスレッドを使うと、Aの処理が終わる前にBを呼び
出すことができます
……それってメリットあるの?
ん、この例だから良さそうに見えないのかな。たとえば

void Use_ファイル一覧取得関数()
{
    ファイル一覧取得関数( "C" );
    ファイル一覧取得関数( "D" );
}

という感じに、〈指定したドライブのファイル一覧を取得する関数〉を呼
ぶ場合、 C ドライブと D ドライブが別のハードディスクなら、両方同時に
アクセスした方が早くなります
そか、これなら同時にやった方が早いよね
ただ、マルチスレッドが難しいのは、これをちゃんと使える形で実装する
のが大変ってところ
そなの? 簡単そうに見えるけど
じゃあまず、出力結果を画面に表示するときはどうすればいい?
ん? まず C ドライブのを出力して、次に D ドライブのを出力して
 D ドライブの取得が先に終わったら?
 C ドライブが取得できるまで待つ……そっか、待たなきゃいけないんだ
そういうこと。つまり

void Use_ファイル一覧取得関数()
{
    ファイル一覧取得関数( "C" );
    ファイル一覧取得関数( "D" );

    両方取得するまで待つ();
    ファイル一覧を出力する( C ドライブ );
    ファイル一覧を出力する( D ドライブ );
}

という感じ
うわ、面倒そう……しかも、待つ、って全然どうやっていいかわからない

それに、この形式で処理すると、ユーザーがキャンセルできません
げ!
そのためにまたマルチスレッド使ったりしてややこしいことになったり
ううう……なんかすごく面倒そう
もうひとつの問題は【同期】です
どうき?
英語で書くと Synchronization 
あ、シンクロってよく言うよね、一緒にタイミング合わせるのとか。それ
が同期?
そういうこと。マルチスレッドは複数の処理が同時に実行されるので、同
時に何かにアクセスする時にはタイミングを取る必要があります。たとえば
先ほどのファイル一覧取得の部分

void Use_ファイル一覧取得関数()
{
    CStringArray cFileListStrAry;

    ファイル一覧取得関数( "C", &cFileListStrAry );
    ファイル一覧取得関数( "D", &cFileListStrAry );
}

という形で cFileStrAry のポインタを渡して、そこにふたつの関数から
ファイルパスを追加してもらう、という処理をしてもらう場合
よくありそうなパターンね
ところが、これは恐らくうまくいきません
へ?
変数に対して複数のスレッドからアクセスすると〈一方が読み込んでいる
間に一方が書き込む〉ということが起きてしまうんです
それって問題?
うん。これは結構難しい問題だから、あとでちゃんと説明します。ここで
は、複数のスレッドからひとつの変数にアクセスする場合には同期を取らな
きゃいけない、ってことを憶えておいて
同期を取る、って具体的には?
たとえば〈スレッドAが cFileListStrAry にアクセスする〉という場
合、〈スレッドBが、スレッドAのアクセスが終わってからアクセスする〉
というふうに待つこと、これが【同期を取る】ということです
待つことが同期?
そういうこと。アクセスできる時にどんどんアクセスする、ってことじゃ
なくて、アクセスの許可が出るまで待つ、ってこと
交通整理みたいな感じ?
うーん、例を挙げるなら、もちつきかな
もちつき?
杵を持つ人がふたり、おもちをこねる人がひとりいるとすると

杵Aが叩く
おもちをこねる
杵Bが叩く
おもちをこねる
杵Aが叩く
おもちをこねる
杵Bが叩く
おもちをこねる
...

というふうにするのが【同期を取る】ってこと。同期を取らない、つまり
待たずにすると

杵Aが叩く
杵Bが叩く
おもちをこねる
杵Bが叩く
杵Aが叩く
おもちをこねる
おもちをこねる
杵Aが手を叩く

大惨事!!
ということになってしまいます
プログラムでもこういうことが起きちゃう?
起きちゃうんです。時には本当に致命的なことに……
あわわわわ……
ウィンドウズでは API レベルで同期を取るシステムが備わっているの
で、それについては本解説で説明します
はーい
さて、今の説明はプログラムの中の話でした。でも実際には、プログラム
とプログラムの間でも、同様の問題は発生します
プログラムとプログラム?
プログラムまるまるひとつ、つまり exe のこと
実行ファイルってこと?
そういうこと。実行ファイルは、当然いくつも同時に実行できるよね
あ” それってある意味、マルチスレッドと同じ……でもさ、確か、他の
実行ファイルの変数ってアクセスできないよね
そう、基本的に変数はアクセスできません。でも変数以外にも共通してア
クセスできるものはたくさんあるでしょ。ファイルとか
あ”……
実はこっちの方がよくあるパターンで、しかも同じように気を付けなきゃ
いけないことが多いんです
確かに、複数立ち上げて複数アクセス、あり得る……
というわけで、説明はこちらの実行ファイルと同期の問題から説明しま

はーい
それと、プログラムそのものの仕組み、みたいなものも説明します
ぷぷぷ、プログラムそのものって、なんか難しそうなんですけど?
うん、難しい
げげ!
たとえば【関数】ってなんなのか
なんなのかって……なんなの?
そういうことの説明
そんなのがマルチスレッドと関係あるの?
大いにあるんです。スレッドっていうのは中身寄りのものだから、そう
いった説明も必要になります
ううう、ちょっと苦手かも……
 C++ でプログラムを作るっていうことはそういうことも知っていないと
いけないってことだから、その辺は覚悟しておいて
はぁい……

/*
    Preview Next Story!
*/
いっつもそうなんだけど、話だけ聞くとそんなに難しそうじゃないよね
マルチスレッドは特にそうかも
……それはつまり……
プログラムに組んでみると難しい、ってこと
げげげ!
というわけで次回
< Version 14.02 プロセスと同期 >
につづく!
ま、次回はまだ概念の話だから大丈夫
……大丈夫なのは次回だけね……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。