スレッド・プログラミングでつきものの関数の再入についてです。
要はヒープ領域のメモリ確保と一緒です。
スレッドがたくさんあるとその1つしかない資源をどう順番に使用できるようにするかの管理が必要の延長上の話で、今回は、ヒープ領域でなくて関数中で記述されるグローバル変数やstatic変数をどう混乱なく扱えるようにするかということです。
(スタック領域はスレッドごとに確保されるわけですので他のスレッドとの競合は問題になりません。)
想定する場面としては、スレッドAがlog_output関数中のstrcpyでbuf[]を編集中に突然割込みが実行されスレッドBが実行されたときを想定します。
void log_output(char* message)
{
..static char buf[256];
..time_t t;
..time(&t);
..strcpy(buf,ctime(&t));
..strcpy(buf+strlen(buf),message);
..puts(buf);
}
そのときスレッドBでも同様にlog_output関数を呼び出しstrcpyでbuf[]を編集し始めたらせっかくスレッドAが処理していた内容が上書きされてしまうわけです。
スレッドAに戻ったときに編集中のbuf[]はスレッドBによって書き換えられてしまったのでもう残っていません。スタック領域ではないので編集途中の情報が残っているわけでもなく、レジスタのように退避されているわけでもありません。
そのため、buf[]をスレッドAが編集しているときにはスレッドBには編集させないような仕組みを作ってやらないといけないわけで、スレッド・ベースでのプログラミングをする際には避けて通れない、知らないとならない問題です。(CGIつくるときはグローバル変数使うのは御法度だよなぁ)
で、その回避策にはいくつかの方法があるのでそれらの方法を詳しくみていくことにします。
①仮想メモリを実装し、タスクをスレッドでなくプロセス化する。
②サービスをOS内部に実装し、システム・コールを利用してプロセス化する。
③関数をリエントラントな構造にする。
④関数内の排他が必要な部分に排他処理を入れる。(割込み禁止にするなど)
⑤再入が発生しない設計にする。
⑥サービスをスレッド化する。
要はヒープ領域のメモリ確保と一緒です。
スレッドがたくさんあるとその1つしかない資源をどう順番に使用できるようにするかの管理が必要の延長上の話で、今回は、ヒープ領域でなくて関数中で記述されるグローバル変数やstatic変数をどう混乱なく扱えるようにするかということです。
(スタック領域はスレッドごとに確保されるわけですので他のスレッドとの競合は問題になりません。)
想定する場面としては、スレッドAがlog_output関数中のstrcpyでbuf[]を編集中に突然割込みが実行されスレッドBが実行されたときを想定します。
void log_output(char* message)
{
..static char buf[256];
..time_t t;
..time(&t);
..strcpy(buf,ctime(&t));
..strcpy(buf+strlen(buf),message);
..puts(buf);
}
そのときスレッドBでも同様にlog_output関数を呼び出しstrcpyでbuf[]を編集し始めたらせっかくスレッドAが処理していた内容が上書きされてしまうわけです。
スレッドAに戻ったときに編集中のbuf[]はスレッドBによって書き換えられてしまったのでもう残っていません。スタック領域ではないので編集途中の情報が残っているわけでもなく、レジスタのように退避されているわけでもありません。
そのため、buf[]をスレッドAが編集しているときにはスレッドBには編集させないような仕組みを作ってやらないといけないわけで、スレッド・ベースでのプログラミングをする際には避けて通れない、知らないとならない問題です。(CGIつくるときはグローバル変数使うのは御法度だよなぁ)
で、その回避策にはいくつかの方法があるのでそれらの方法を詳しくみていくことにします。
①仮想メモリを実装し、タスクをスレッドでなくプロセス化する。
②サービスをOS内部に実装し、システム・コールを利用してプロセス化する。
③関数をリエントラントな構造にする。
④関数内の排他が必要な部分に排他処理を入れる。(割込み禁止にするなど)
⑤再入が発生しない設計にする。
⑥サービスをスレッド化する。