• ベストアンサー

リエントラント関数

はじめまして。 複数のタスクで利用されるような関数を作成しようと思っています。 この関数をFuncAとします。 void FuncA() {   int a;   int b;   int c;   処理1;   処理2;   処理3;   処理4; } タスクは優先度低のタスクAと優先度高のタスクBがあるとします。 タスクAがこのFuncAの処理2を行っている最中に、 タスクBがこのFuncAを呼び出すとタスクBで先にFuncA処理をしてから、 タスクAに戻って続きの処理3を行うと思います。 このとき、タスクAで使用していたローカル変数a,b,cはどっかに退避されているのでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8536/19410)
回答No.4

>このとき、タスクAで使用していたローカル変数a,b,cはどっかに退避されているのでしょうか? auto変数はスタックに作成されるので、事実上、退避されるのと同じ。 register変数はコンテキストスイッチで自動的に保存、復元される。 「スレッドセーフな関数」とは「静的またはグローバルな変数を、参照、操作してない関数」なので、静的またはグローバルな変数にアクセスしてればアウト。当然、ポインタを用いて「関数外で確保したメモリ」にアクセスしている場合もアウト。 また「スレッドセーフが保証されてない関数」を呼んでいる場合、自分自身も「スレッドセーフが保証されてない関数」になってしまうので、その場合もアウト。 たいていの「C標準ライブラリ関数」は「スレッドセーフが保証されてない関数」なので「C標準ライブラリ関数を呼んだらアウト」と思って間違いない。 上記のように「変数だけ安全でも、ちっとも安全じゃない」ので、ご注意を。 そういう訳で ・静的またはグローバルな変数を、参照、操作してない ・関数外で確保したメモリを、参照、操作してない ・スレッドセーフが保証されてない関数を呼んでいない ・C標準ライブラリ関数(スレッドセーフが保証されている物を除く)を呼んでいない なら、両方のタスクから同じ関数を呼ぶ事が出来ます。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (3)

  • S117
  • ベストアンサー率40% (18/45)
回答No.3

自動変数が複数のスレッド間で独立であるかという質問でしょうか。 それとも、実装例についての質問でしょうか。 前者への回答 自動変数は別のスレッドとは干渉しません。(ポインタなどで意図的に共有しない限り) 後者への回答 スレッド間で変数は独立しますが、では関数呼び出し時に退避されるのでしょうか。 自動変数はほとんどの実装で、コールスタックに確保されます。 (コールスタック自体の説明は参考URLで。) マルチスレッドの場合、このコールスタックをスレッドごとに独立させて用意することになります。そうすると、自動変数は全く関係のない箇所に独立して用意されますので、「退避させる必要はない」のです。

参考URL:
http://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%BC%E3%83%AB%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF
全文を見る
すると、全ての回答が全文表示されます。
  • massano1
  • ベストアンサー率40% (4/10)
回答No.2

FuncAで取っている変数は大丈夫です。 (「int a,b,c」はstaticでは無いので別に取られます) 但し、内部で呼び出す処理で外部スコープの変数(グローバル変数等)を 参照した場合は動作が変わるので「FuncA全体が安全か」は(この情報 だけでは)不明です。

全文を見る
すると、全ての回答が全文表示されます。
  • Tasuke22
  • ベストアンサー率33% (1799/5383)
回答No.1

リエントラント・・・懐かしい言葉に思わず出てきました。 リエントラントを要求されるということは、複数のタスク から1つのモジュールがコピーされないで呼ばれるので、 内部変数があれば、即アウト、です。 タスク毎にテーブルなどを持たせ、その領域を使う仕組み でなければいけません。 簡単な方法ですと、呼出し引数に作業域を付ける、とかで す。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 関数ポインタの型をtypedefしたとき

    C言語において、関数ポインタの型をtypedefで作ると、 typedef int (*MyFunc)(int*,int*); と宣言でき、関数ポインタの変数は、 int FuncA(int* a, int* b) { ~ } void main_loop() { MyFunc pf = FuncA; ~ (*pf)(pa,pb); } というように使うと思います。 ここで疑問なのですが、この実際に呼び出される関数、FuncAの定義に、typedef(ここではMyFunc)を使えないものでしょうか? 同じことを2回やっているようで、無駄に思えてしまいます。

  • C言語のグローバル変数の初期化について

    C言語において int a = 1; // 動的グローバル変数 static int b = 2; //静的グローバル変数 funcA(){ int c = 3; // 動的ローカル変数 static int d = 4; //静的グローバル変数 ・ ・ ・ } 上記のように各種変数を初期化したとします。 "c"のような動的ローカル変数であれば、funcA()が呼ばれたときに毎回初期化されますよね? では ・"d"のような静的ローカル変数は、初めてfuncA()が呼ばれたときに初期化されるのですか? ・"a","b"のyほうなグローバル変数は、どのタイミングで初期化されるのですか? 以上2点について伺いたいと思います。 ちなみに、組み込み機器むけのソフトウェアを想定しています。

  • 関数の最初の変数有効期限について

    最近C言語を勉強しているのですが変数の有効範囲について教えてください。 ローカルやグローバル変数があるのが分かって関数内の変数も関数内でのみ有効というのも理解したのですが int a( int b ); という関数の最初に書く括弧の中のbと宣言している変数も関数内に含まれているという事で良いのでしょうか?。

  • C言語で、記憶クラス指定子extern・staticを関数に指定

    C言語の本に、「関数の定義と呼び出す側が別ソースファイルの場合、プロトタイプはヘッダーファイルに書き、定義側と呼び出し側の両方でインクルードしましょう」ということが書かれていました。 例えば、 ===code1a.c=== extern void funcB(int); static void funcA() { funcB(1); } ===code1b.c=== void funcB(int a) { printf("%d\n",a); } このような場合には、もしcode1b.cの中の関数funcBに引数を追加した場合、再コンパイルしても気づかないのでよくない。 そこで、次のようにヘッダーファイルを作り、プロトタイプはそこに書くべきだ。 ***code2b.h*** extern void funcB(int); ***code2a.c*** #include "code2b.h" static void funcA() { funcB(1); } ******code2b.c**** #include "code2b.h" void funcB(int a) { printf("%d\n",a); } 記述は以上のようなことです。 #include "code2b.h" とは、 extern void funcB(int); が書いてあるのと同じだと思います。 私が思ったのは、本の勧める方法では、 funcBを定義しているcode2b.cで、プロトタイプの記憶クラス指定子が、externになっているが良いのか(externとは、別のソースファイルで定義されているという意味ではないか)ということです。 extern, staticは、プロトタイプに書くべきなのか、関数の定義に書くべきなのか、も両方に書くべきなのでしょうか。 私の処理系では、 ・プロトタイプ宣言でexternを付けて関数定義でstaticを付ける、 ・staticを付けた関数を他のソースファイルで呼ぶ、 などの明らかに矛盾する場合は、コンパイルエラーになります。 でも、extern単独での役割はなさそうです。 他の処理系でも同じでしょうか。 (main等省略)

  • 関数ポインタにvirtual関数を与えたいです

    //関数ポインタについて質問させてください。 //error C2440: '=' : 'void (__thiscall A::* )(int,int)' から 'void (__cdecl *)(int,int)' に変換できません。 //というエラーが出ます。 //どうすればいいのか教えてください。 //よろしくお願いします。 #include<stdio.h> class A { public: void (*aaa)(int a,int b); virtual void test(int a,int b)=0; virtual void test2(int a,int b)=0; void execute() { aaa=test;//error C2440 } }; class B : public A { public: void test(int a,int b) { printf("test"); } void test2(int a,int b) { printf("test2"); } }; int main() { B b; b.execute(); b.aaa(2,3); return 0; }

  • C言語での単体テストの作成について質問です。

    C言語での単体テストの作成方法がわからずに困っています。 以下のようなA.cの中のFuncA関数のテストを作成しています。 /*** A.c ********************/ #include "B.h" int FuncA (int n) { int temp; if (FuncB() == true) temp = n * 2; else temp = n / 2; return temp; } /****************************/ FuncA関数は中でB.c内のFuncB関数を読んでいますが、 これは、B.h、B.cに定義されている関数です。 このFuncB関数は本物のソースを使用せず、スタブを使用してテストを作成しています。 FuncB関数のスタブは以下のように考えています。 /*** BStub.h ********************/ extern bool retVal extern bool FuncB_Stub(void); /******************************/ /*** BStub.c ********************/ #include "BStub.h" bool retVal; bool FuncB_Stub(void) { return retVal; } /******************************/ できる限り、A.cに単体テスト用のコードを埋め込まずにテストを作成したいのですが、 FuncA関数がFuncB関数ではなく、BStubのFuncB_Stub関数を呼び出すようにするには どのようにしたらよろしいでしょうか?

  • 関数の引数に丸カッコがあるとき

    C言語のアルゴリズムのサンプルのソースを見ていて 今まで見たことの無い形式があったのですが、 どのように調べればよいものか解らず 調べようにも調べられなくて困ってます。 具体的には以下のような感じの関数があるのですが、 これはどういった意味なのでしょうか? ご存知の方がいらっしゃれば アドバイスご伝授をよろしくおねがいします void sample( int a, int b(int, int), void c(int, int) ){  ... // ここに処理 }

  • 引数に二重配列のある関数について

    void calc(int *a,int b,int c){ a[0]=b+c; a[1]=b-c; } void main(void){ int x[2]; int y=2,z=5; calc(x,y,z); printf("x[0]=%d,x[1]=%d\n",x[0],x[1]); } 上のように引数が普通の配列の関数ならできるのですが, 引数が下のような多重配列になるとエラーが出てしまいできません。 void keisan(int **a,int b,int c){ a[0][0]=b+c; a[0][1]=b-c; a[1][0]=b*c; a[1][1]=b/c; } void main(void){ int x[2][2]; keisan(x,6,2); printf("x[0][0]=%d,x[0][1]=%d\n",x[0][0],x[0][1]); printf("x[1][0]=%d,x[1][1]=%d\n",x[1][0],x[1][1]); } 引数に多重配列を使った場合の関数の作り方について教えてください. お願いいたします.

  • PHP 関数内の変数のスコープについて

    宜しくお願いします。 関数A内で作成したローカル変数 「a」 を、 その関数A内で作った関数Bで、変数「a」を操作しようと思います。 簡単に書くとこうです。 function A(){ $a = array(あ、い、う); function B(){ $a = array(い、う) }   ※$aを使っての処理 } <試してみたこと> 関数B内で、global $a として、変数をグローバルにしましたが、関数Bの操作は反映されませんでした。 retun で戻せばよいとも、もちろん考えましたが、 処理の都合上、どうしてもグローバルに扱いたく思います。 とても、大雑把な質問形式で申しわけございませんが、何卒、ヒントを下さいませ。

    • ベストアンサー
    • PHP
  • C言語:引数の型だけ異なる関数を一つにまとめる方法

    以下の引数の型だけ異なる関数を、どうにかして一つにまとめたいのですが、 何か良い方法はないでしょうか? void funcA(_MNGR_TAG mngr){ 処理X; } void funcB(_COPY_MNGR_TAG mngr){ 処理X; } 補足: ・_NODE_TAGと_COPY_NODE_TAGは構造体です。ただし中身は異なります。 ・(引数名が同じため)funcAとfuncBで行っている処理は全く同じです。 注意事項: 関数テーブルやC++言語を使用する方法は除いて下さい