質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

2152閲覧

リエントラント、スレッドセーフについて(Wikipediaのソースコード例について)教えて欲しいです

Tteratail

総合スコア36

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2021/10/12 14:25

リエントラントについて調べてて、以下のWikipediaのリエントラントでもスレッドセーフでもないソースコード例と、その改善例が紹介されてました。
https://ja.wikipedia.org/wiki/リエントラント

次の例の swap() 関数は、リエントラントではない(同時にスレッドセーフでもない)。したがってこれを割り込みサービスルーチン isr() で使用すべきでない。

int t; void swap(int *x, int *y) { t = *x; *x = *y; // ここでハード割り込みが起きて isr() が呼び出される可能性がある。 *y = t; } void isr() { int x = 1, y = 2; swap(&x, &y); }

次のswap関数はリエントラントかつスレッドセーフである。

void swap(int *x, int *y) { int t; t = *x; *x = *y; // ここでハード割り込みが起きて isr() が呼び出される可能性がある。 *y = t; } void isr() { int x = 1, y = 2; swap(&x, &y); }

確かに最初の例は変数tがグローバル変数であり他の箇所で書き換えられてしまう可能性がありリエントラント性が阻害されてしまう、ということは分かるのですが、最初の例のコメントの箇所で割り込みが起きて isr()がコールされたとしても、上記の例だとその結果(swap()後のxyの値)は改善例の結果と変わらないですよね?
そのため例としてしっくり来ず、もしかしたら自分の理解が間違っているのかと思って確認したい次第です。
上段の例では,
まずグローバル変数tが静的領域に0で初期化され、
main()からirs()がコールされたとして、
ローカル変数xyがスタック領域にそれぞれ1と2で初期化れさて積まれて、
swap()がコールされ、
txを代入、xyを代入(この時点でtの値は"1"、xの値は"2")、
と、ここでハード割り込みによってirs()がコールされ
新たにローカル変数xyがスタック領域にそれぞれ1と2で初期化されて積まれて、
swap()がコールされ、
txを代入、xyを代入、ytを代入(この時点でtの値は"1"、xの値は"2"、yの値は"1")。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2021/10/13 01:45

> main()からirs()がコールされたとして main()からirs()をコールする,といった記述は wikipedia にはどこにもないように見えますが, 何故に, そのようにされたこととして 話を進めているのですか? (結果として同じになるような特殊例を取り上げたならば同じになる → それが何だというのか?)
guest

回答3

0

ベストアンサー

もしかしたら自分の理解が間違っているのか

はい。間違っています。

main()からirs()がコールされたとして

まず irs() ではなく isr() です。この関数名には明確な意味がありまして、割込みサービスルーチン Interrupt Service Routine を略して isr() なのです。
割込みサービスルーチンISRはハード割込みが発生した時に呼ばれます
呼ばれる、と言っても普通の関数呼出しと違い、ISR関数を呼出すプログラムコードはありません。割込みを受けるとCPUはISRを実行する、そのような動作をするハードウェアの仕組みがCPUの中にあります。

** main() は isr() をコールしません**。

問題が起こる状況は次のようなものです。
まず main() 関数。

C

1int main(void) 2{ 3 int a = 3, b = 4; 4 swap(&a, &b); 5 ...
  1. swap(&a, &b) を実行中、当該箇所でハード割込みが発生する
  2. isr() が動く=割込む。そこで swap(&x, &y) を呼び実行する
  3. isr() の処理が終了すると、先ほど割り込んだ箇所に動作が戻る
  4. swap(&a, &b) の中の、やり残していた *y = t を実行する

動作をトレースしてみてください。
isr() は x = 1, y = 2 を交換し x = 2, y = 1 になりますが、
main() は a = 3, b = 4 を交換したつもりが a = 4, b = 1 となります。

投稿2021/10/13 03:31

rubato6809

総合スコア1382

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Tteratail

2021/10/13 07:57

コメントありがとうございます。 `isr`はハード要因の割り込みサービスルーチンで`main`からはコールされないと理解しました。 ソースコード例もありがとうございます。 >main() は a = 3, b = 4 を交換したつもりが a = 4, b = 1 となります。 そのような動作になることも理解できました。勉強になりました。
guest

0

最初の例のコメントの箇所で割り込みが起きて isr()がコールされたとしても、上記の例だとその結果(swap()後のxとyの値)は改善例の結果と変わらないですよね?

メインルーチン下で、x=3,y=4で実行された場合は結果は変わってしまいますね

投稿2021/10/12 22:25

y_waiwai

総合スコア88163

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Tteratail

2021/10/13 07:51

コメントありがとうございます。 >メインルーチン下で、x=3,y=4で実行された場合は結果は変わってしまいますね 他の皆さんのコメントからも今はそのように理解しました(質問時点では自分の常識不足で isr()が先にコールされることを起点に考えていました)。
guest

0

確かに最初の例は変数tがグローバル変数であり他の箇所で書き換えられてしまう可能性がありリエントラント性が阻害されてしまう、

そこはあまり関係な無くて、同時に複数のswap呼び出しが発生した場合に、唯一の変数を共有しているからというのが問題点です。

そのため例としてしっくり来ず、

決まった値で呼び出すswapが同時に行われても結果に違いが無いというのはその通りなので、例が適当で無い、もしくは説明が不足しているということだと思います。

最初のswap呼び出しがisrからであることは明記されていないですが、これが、

C

1int p=9, q=10; 2swap(&p, &q);

からの呼び出しであったとすると、途中でコード中のisr()からの呼び出しが発すると、q1になってしまいます。というのが問題点ですね。

最初のswap呼び出しが何であるか明記されていないのが例のよくない点でしょうね。
「したがってこれを割り込みサービスルーチン isr() で使用すべきでない。 」という記述が、最初のswap呼び出しもisrからであることを言ってるのであれば、例が適当で無いと言うことになります。ただ、そう言っているとも言い切れないし、isrという言葉を「割り込みサービスルーチン一般」の意味で使っているとも言えなくないので、なんとも言いがたいところです。

投稿2021/10/12 15:20

otn

総合スコア86285

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2021/10/13 01:38

> 最初のswap呼び出しが何であるか明記されていない Wikipediaの文章を上から読めば,文脈上,あえて明記する必要があるとも思えないのですが. これを > 最初のswap呼び出しもisrからである ように「わざわざ」読むのは,いくらなんでも無理矢理すぎる. (そりゃあ「そういうことが起きる場合もある」だろうけど,あえてその場合だけを取り上げて論じる文脈でないことは自明ではなかろうか)
Tteratail

2021/10/13 07:46

otnさん、 私のレベルの低い質問に丁寧に回答してくださりありがとうございました。おかげで理解できました。 fanaさん、 `isr`が割り込みサービスルーチンということもちゃんと理解しておらず、wikipediaのソースコード例を見たときに単純に`isr`が`swap`をコールするコードになっていたので、`isr`が先にコールされている前提で勝手に考えていた次第です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問