• 締切済み

【組込み】割り込み中のstatic変数について。

ハード的な割り込みの入る可能性のあるシステムにおいて static変数を更新する間は割禁をかけるように指導されたのですが 理由がよく分かりません。 値が変えられる可能性があるとのことなのですが 少し詳しく教えていただけるとありがたいです。 (autoは平気でstaticはダメな理由、書き変わる際のシーケンス等) 以上、よろしくお願いします。

みんなの回答

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.4

zwiさんが一通り解説してくれたので、もうあまり書くことはないのですが... #2でも書いたように、代入に関しては排他制御が不要の場合もあり得ます。ただし、sig_atomic_t型を使う場合を除き、移植性に配慮するなら排他制御を行った方が無難です(パフォーマンスとの相談になります)。 基本的には、割り込みは命令と命令の間に発生しますが、アーキテクチャによっては、ブロック転送のような高級命令の実行途中で割り込みが発生することもあるので要注意です。また、割り込みだけでなく、DMA転送なども起こりえますので、排他制御の必要性を考慮する場合はお忘れなく。 なお、割り込み云々といっていることからしても、スレッド間の排他制御も割り込み禁止で行うことが出来る可能性は高いと思います。 マルチプロセッサの環境で、プロセッサ間の共有メモリに配置された変数を更新する場合はさらに注意が必要です。このような場合、たとえアトミックオペレーションだとしても、メモリアクセスが分割される場合にはやはり排他制御が必要になります。 また、排他制御は割り込み禁止では不十分で、スピンロックを使うか、OSの支援があるならセマフォやミューテックス等の機構を使う必要があります。

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.3

>割り込みハンドラ内で同じ変数が呼ばれる可能性がなければ、特に割禁にする必要はないのでしょうか? 同じ変数というか、同じアドレスに対して参照や書き換えをしていない限りは割り込み禁止にする必要はありません。 では、なぜ割り込み禁止にする必要があるか考えて見ましょう。 割り込みはマシン語の1命令単位で発生しますから、変数の処理がマシン語の1命令で完結しない場合は、割り込み禁止にする必要があります。 例えば、加算で a=a+b; はC言語なら1命令ですが、機械語レベルで見れば数命令必要です。 a+bを代入する前に割り込んで、割り込み先でaを書き換えても、割り込みから戻ってきた後aへの代入が起こるので、割り込み先で書き換えた値はロストしてしまいます。 これはスレッドでも同様ですが、スレッドはセマフォ等の同期処理で排他制御します。 volatileが必要な理由は、こちらを参照してください。 http://www.kumikomi.net/article/explanation/2003/10kumi/13.html >ここでの排他制御は、ハード的な割り込みが入る可能性から考えて >セマフォを握ってれば大丈夫。というレベルではないですよね? ハード的な割り込みとの排他制御でセマフォを使うことは出来ません。使うと必ずデットロックします。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

更新中に割り込みが発生した場合、割り込みハンドラで同じ変数を更新または参照を行う可能性があるためです。 ただし、単なる代入の場合には、sig_atomic_t型のように、代入がアトミックオペレーションで行われることが保証されている型に限れば、割り込み禁止等の排他制御は不要です。 なお、割り込みハンドラや他のタスクと共有する変数は、排他制御の他にvolatile修飾子を付ける必要があります。 > (autoは平気でstaticはダメな理由、書き変わる際のシーケンス等) コンパイラの出力結果を見ればすぐに理解できるはずです。

hiro0163
質問者

補足

回答ありがとうございます。 割り込みハンドラ内で同じ変数が呼ばれる可能性がなければ、特に割禁にする必要はないのでしょうか? (割り込む側の都合なので、対応は必要だと思いますが、理由はそれ以外にないかを確認したいです。) >コンパイラの出力結果を見ればすぐに理解できるはずです。 これは割りついている領域が違うからという見解で正しいでしょうか? お手数ですが、よろしくお願いします。

  • master000
  • ベストアンサー率33% (16/48)
回答No.1

マルチスレッドでプログラミングしているということですね。 排他制御をしなさいということだと思います。 排他制御ができていれば割り込み禁止でなくてもよいと思います。

hiro0163
質問者

補足

回答ありがとうございます。 ご意見通り、マルチスレッドでのプログラミングになります。 ここでの排他制御は、ハード的な割り込みが入る可能性から考えて セマフォを握ってれば大丈夫。というレベルではないですよね?

関連するQ&A

  • static宣言について

    現在、c言語とDXライブラリを使ってゲームを製作しています。 http://okwave.jp/qa/q8270456.html 前回、このような質問をさせていただき、原因らしき箇所を突き止める所までいきました。 と言いますのも、配列の要素を指定する箇所(分かり辛かったらすいません。要素数ではありません)に、static宣言された変数を入れるとなぜかプログラムが強制終了されてしまうのです。 加えて、DXライブラリのGetColor関数にも返ってきた色をStatic宣言された変数に格納すると、何故か指定された色と違う色が出てしまうことが分かりました。 なんとか、その関数が終わる度に値を格納したかったので、色々試しました。 直接Static宣言されていない変数を間に噛ませてみたり、同じcpp内にわざわざ別の関数を用意して、そちらでStatic宣言し、値を返してみたり、と色々とやったのですが上手くいきませんでした。 ****************************************** int hairetu[20]; Static int z = 0; int x = z-1+1 hairetu[x] = zahyouX; (static宣言された変数zでhairetu[]の[]内を指定しようとするとダメ) (上記のように意味のない計算をさせてstatic宣言されていない変数を間にかませてもダメ) ****************************************** 結局の所、別のcppを用意して、ただ一つのStatic変数を+1していくだけの関数をくみ上げた所、上手くいったのですが・・・。何故このような事が起きるのでしょうか。 Static宣言された変数の決まりごと、もしくは、このような状態になってしまった原因など、見当がつきましたら教えていただけると有難いです。よろしくお願いします。

  • 変数について

    プロパティファイルから読み取った値をほかのクラスから使いたいと考えて以下のような2つのクラスを作成しました。 [プロパティ読み取り] public class Admin{ public static String HOST; public static String ACCOUNT_NAME; public static String ACCOUNT_PASSWD; /** * * @throws java.io.IOException */ public Admin() throws IOException{ try{ // read from properties file.      Properties pro = new Properties(); pro.load(new FileInputStream("プロパティファイル")); HOST = pro.getProperty("host"); ACCOUNT_NAME = pro.getProperty("account.name"); ACCOUNT_PASSWD = pro.getProperty("account.password"); }catch(Exception e){ System.out.println(e); } System.out.println("Host: "+ HOST); System.out.println("User: "+ ACCOUNT_NAME); System.out.println("Password: "+ ACCOUNT_PASSWD); } } [変数使用] public class Update { public static void main(String[] args) { System.out.println("Host: "+ Admin.HOST); System.out.println("User: "+ Admin.ACCOUNT_NAME); System.out.println("Password: "+ Admin.ACCOUNT_PASSWD); } } Adminクラスの出力では、変数に正しい値がセットされていますが、Updateクラスではnullが返ります。 スコープの問題かと思うのですが、どこをどのように改良したらよいかわかりません。 nullではなく、正しい値を取得するにはどのようにすればよいでしょうか

    • ベストアンサー
    • Java
  • 違うクラスからの変数の共有化

    一つのクラスの中にある変数の値を、二つの別なクラスから呼び出して、その二つのクラスのどちらから変数を参照しても同じ値が帰ってくるようにしたいのですが、いろいろ調べてもできなかったので質問させていただきますm(_ _)m // 共有化させたい変数を持つクラス // Var.java public class Var{  public static int i;  public Var(int i){ this.i = i; }  public Var(){}  public static void getI(){   return i;  } } //クラス1 //Class1.java public class Class1{  Var var = new Var(1); } //クラス2 //Class2.java public class Class2{  Var var = new Var();  System.out.println(var.getI()); } とした場合、Class1を実行し、次にClass2を実行すると、クラス1で定義した変数の値である 1 が戻ってくるようにしたいのですが、上記の方法では、Class2を実行すると結果は 0 になってしまいました。 まだまだ習い始めたばかりでいまいちstaticを使い切れていないと思います・・・ たとえば、PrintStreamクラスの public static final PrintStream out というのはどこから参照しても同じ結果なのでそのようなやり方で大丈夫だろうと思ったのですが・・・ このような方法では共有化させることはできないのでしょうか?またできないのでしたらほかのやり方がもしあった場合は教えていただきたいと思います。 どうかお願いします。

    • ベストアンサー
    • Java
  • 動的に変数をセット後他クラスから参照する場合

    コンストラクタで変数にセットした後 他のクラスでインスタンスを生成することなく セットした変数を参照したいのですが、 staticにすると、他クラスで変数を変更することも できてしまいます。他の方法がありますでしょうか? 変数はprivateにして、getterで取得するという方法も 考えられますが、static finalな変数として扱う方法が あるか、お分かりの方いらっしゃいましたら教えてください。 Javaを初めて1ヶ月なので、見当違いの質問でしたらご指摘ください。 例) Class A{  static final String aaa; A(String paraStr){ aaa = paraStr; } } Class B{ static void main(String[] args){ new A("test"); } } Class C{ void chStr(){ System.out.println(A.aaa); A.aaa = "changeStr" System.out.println(A.aaa); } } 期待する値 test test もしくは、実行時にfinalの値は変更できない等のException 宜しくお願いします。

    • ベストアンサー
    • Java
  • Cのローカル変数でstatic以外の使い方?

    C言語の課題について教えてください [課題] 以下の関数がある。各関数の引数、変数は自由に設定していい ・int main() ・void func() ・Point *get() { /* 構造体のアドレスを返す */ } ・構造体 typedef struct { int x; int y; int h; int w; }Point; 問題 main関数から、func関数を経由して、get関数を経由し値を取得し、表示する 以下が考えたソースになりますが、これだと、 ローカル変数でstaticを使っているので、get関数が固定値ではなく、 取得のたびに値が変わるような場合には、だめだといわれました。 考えたのですがよくわからないので、どういう場合に駄目なのかと、 どのように修正すればいいのか教えてください。 #include <stdio.h> typedef struct { int x; int y; int h; int w; }Point; void func(Point **); Point *get(); int main(void){ Point *get; func(&get); printf("get.x:[%d]\n",get->x); printf("get.y:[%d]\n",get->y); printf("get.h:[%d]\n",get->h); printf("get.w:[%d]\n",get->w); return 0; } void func(Point **pw){ *pw = get(); printf("Wrapper: pw==%p\n",pw); } Point *get(void) { static Point pget; pget.x = 2; pget.y = 2; pget.h = 30; pget.w = 40; return &pget; }

  • 非staticフィールドを参照できない理由とは

     java勉強中です、宜しくお願いします。  下のようなプログラムを書き「Test1」をコメントアウトしたら、 「非staticフィールドをstatic参照できません。」というエラーが 出ました。  「Test1 t」をグローバル変数で定義したのですが、やはりを 「static」からは見れないということでしょうか。  「main」は特別な関数というのは分るのですが、staticフィールドとか クラスオブジェクトしか、main()からは覗けないという設計思想(?) とかはどのようなものなのでしょうか。  逆に覗けるのが可能ならばどのような不都合が生じるのでしょうか。  何かしら非常に不便を感じて使い勝手が悪いという気がして仕方ない のですが、特別にこうしなけらばならないとか、今までの他の言語であ った不具合(ex 隠蔽機能)を更に強化したためとかと言う理由があるの でしょうか。  ========================================================== public class Test1 { Test1 t; void calc() { int a = 2; int b = 3; System.out.println(a+b); } public static void main(String args[]) { /*Test1*/ t = new Test1(); t.calc(); } }

    • ベストアンサー
    • Java
  • String型の変数を使った問題

    すごく簡単なプログラムのはずで、初歩的な質問で申し訳ありませんが、教えていただければと思います。 問題: 以下の場合の処理を行うプログラムを作成せよ。 (1)String型の変数を作成し、苗字を格納する。(値は直接書き込む) (2)String型の変数を作成し、名前を格納する。(値は直接書き込む) (3)(1)で作成した苗字を持つ変数と、(2)で作成した名前を持つ変数を結合して出力。 (4)「苗字は'((1)で作成した変数の値)'です。名前は'((2)で作成した変数の値)'です。」と出力。 出力結果: C:\>java Name いわたてつお 苗字は'いわた'です。名前は'てつお'です。 C:\> 上記のプログラムを作成しようとしたのですが・・・ import java.io.*; class Name { public static void main(String[] args)throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str1 = br.readLine(); String name1 = str1; String str2 = br.readLine(); String name2 = str2; System.out.println(name1 + name2); System.out.println("苗字は\'" + name1 + "\'です。名前は\'" + name2 + "\'です。"); } } ↑これではいくら変数を2つ作成しても、書き込んだ文字が全て 苗字の変数に格納されてしまってちゃんと出力出来ないという事は 分かるのですが、どうやったらちゃんと苗字と名前に分かれて 出力されるのか分からないので、教えてください。 なんとなく文法的にも間違っている気が・・・ ホント初歩的な質問ですみません!

    • ベストアンサー
    • Java
  • 変数を取得したい

    例えば、次のようなプログラムで1個の乱数を取得します。その取得した乱数の一番下の桁の数字(0~9)だけに着目し、変数iなどに値を取得するといったことは出来ますでしょうか? import java.util.*; public class RandomTest { public static void main(String[] args) { Random generator = new Random(); for(int i=0; i<1; i++){ int ran = generator.nextInt(); System.out.println(ran); } } }

    • ベストアンサー
    • Java
  • for構文内の変数について質問

    以下のソースコードの一部を見た上で私の質問に答えてください public class A { public static void main(String arg[]){ for(int i=0; i<2; i++){ for(int k=0; k<3; k++){ System.out.println(i+"-"+k); } } } } このソースコードを実行すると、以下のような数字がeclipsのコンソール画面に表示されます。 0-0 0-1 0-2 1-0 1-1 1-2 質問:変数kの値は、1、2と増えているに関わらず、再び0に戻ってますよね? 何故変数の中身の数値がクリアーされてるのですか? 質問2:for構文を一度脱出すると、変数の中身はクリアーされるのですか?それとも『ローカル変数の中身だけクリアー』されるのですか?

    • ベストアンサー
    • Java
  • global変数の取り扱いについて

    石井と申します。 表題の件についてご質問させて頂きます。 現在、DBにセッション情報を保持させるように セッション・プログラムを作っているのですが、 以下のように、セッション関数を登録しているとして、 session_set_save_handler( 'my_sess_open', 'my_sess_close', 'my_sess_read', 'my_sess_write', 'my_sess_destroy', 'my_sess_gc' ); my_sess_read が呼ばれたときに、 DBに登録されていたセッション値をグローバル変数var1に保存し、 my_sess_writeが呼ばれたときに、 my_sess_writeの引数で指定されたセッション・データが、 var1と違うなら、DBを更新させるというふうにしたいと考えています。 それで、質問なのですが、 phpでいうグローバル変数var1は、他人からも参照が可能になっているのでしょうか? (値がスレッド間で共有されるのか?) 別の例えで言うなら、phpのグローバル変数は javaでいうstatic修飾子のような動きをするのでしょうか? 以上、宜しくお願い致します。

    • 締切済み
    • PHP