- PR -

スタックオーバーフローを防ぐ方法について

投稿者投稿内容
セラフ
ベテラン
会議室デビュー日: 2005/12/01
投稿数: 95
お住まい・勤務地: 東北の顔の形といえば
投稿日時: 2008-03-11 14:29
WinXP + VB.NET 2005 + シリアルI/O によるハードの制御を行うPGを作成しているのですが、ループがスタックを食いつぶしてしまい、スタックオーバーフローを発生させてしまって困っています。どなたかわかる方がいらっしゃいましたら、お知恵をお貸しください。

現象は、実行開始から20時間ほどでスタックオーバーフローが発生し、スレッドが落ちてしまうというもので、プログラム自体はWinodwsサービスとし作成してあります。

現象が発生するのは以下の部分で、シリアルポートは前段階で開いたままになっています。また、サービスのスレッドとは別スレッドで動作しているので、スタックオーバーフローが起きても、サービス自体は生きています。

************************************
DO

IF 割り込み命令が存在すれば THEN
変数 = 割り込み命令文
ELSE
変数 = 生存確認文
END IF

シリアルで『変数』送信

try
シリアルで受信
catch
シリアル通信がタイムアウト、もしくは返信文異常で
エラーログ書き出し。
end try

LOOP サービスの停止が無ければ
************************************

明らかにloopがスタックを食いつぶしているのはわかっているのですが、常に通信をまわしておく必要があるため、タイマースレッド等では要件を満たせず、もしかしたらVBがスタックを巧くやりくりしてくれるかも??っと淡い期待をもって書いてみましたが、やはりNGで困りはてています。

タイマースレッドで1ミリ秒間隔でやればいいのでは?っと思われると思いますが、
ハード側がその1ミリ秒が待てないガマンできない子で、しかも通信レスポンスの速度を求められています。速度を犠牲にせず、スタックオーバーフローを防ぐ手法のアイディアをお持ちのかたがいらっしゃいましたら、是非おしえてください!!

※必要な情報があればわかる範囲であげさせていただきますので、ご指示ください。
indigo-x
大ベテラン
会議室デビュー日: 2008/02/21
投稿数: 207
お住まい・勤務地: 太陽の塔近く
投稿日時: 2008-03-11 14:43
見る限りでは問題なさそうなので

もう少しコメントアウトして原因を限定した方がよいのでは

例)送受信はコメントアウトして放置する
例)try-catchをとる
セラフ
ベテラン
会議室デビュー日: 2005/12/01
投稿数: 95
お住まい・勤務地: 東北の顔の形といえば
投稿日時: 2008-03-11 15:01
>>indigo-xさん
返信ありがとうございます。

>例)送受信はコメントアウトして放置する
>例)try-catchをとる
残念ながら、既に試行済みでした。

エラーまでの時間が伸びはするものの、エラー自体は間違いなく発生してしまいます。
サービスが停まるまで単純に無限ループしてしまうため、どうしてもこのコーディングではスタックオーバーフローが発生してしまう様子です。
どせい
大ベテラン
会議室デビュー日: 2006/10/25
投稿数: 145
投稿日時: 2008-03-11 15:21
引用:

セラフさんの書き込み (2008-03-11 14:29) より:
タイマースレッドで1ミリ秒間隔でやればいいのでは?っと思われると思いますが、
ハード側がその1ミリ秒が待てないガマンできない子で、しかも通信レスポンスの速度を求められています。



答えでなくてごめん。
WindowsXP(たぶんProfessional?)で、リアルタイム処理ってできたっけ?

1ミリ秒タイマーですら待てないのならこっちのOSとか、リアルタイム処理をサポートしたものを検討してみてはいかがかな?
http://www.microsoft.com/japan/windows/embedded/techinsights/realtime.mspx

[追記]
って、さらにごめん。
引用部分にだけ反応してリアルタイムOSとか書いちゃったけど、
対応してる開発ツールで作り直す手間とか考えてなかった。脱線させてすまない。
[/追記]

[ メッセージ編集済み 編集者: どせい 編集日時 2008-03-11 15:32 ]
セラフ
ベテラン
会議室デビュー日: 2005/12/01
投稿数: 95
お住まい・勤務地: 東北の顔の形といえば
投稿日時: 2008-03-11 15:54
>>どせいさん
お返事ありがとうございます。
Motherシリーズを思い出してしまうかわいい名前ですねw

リアルタイムOSはむしろ「つかいたい」です(泣)
この仕事請けた時点ではそんな用件もなく、「VBで軽く作っておわそうぜ」な感じで請けたのですが、ふたを開けたら最後に困った要件が挙がってしまった感じです。

おっしゃることは正論ですが、大人の理由でいまさら返られないという良くあるアレです・・・
変えられるなら変えたい(号泣)
Yam
大ベテラン
会議室デビュー日: 2003/09/13
投稿数: 179
お住まい・勤務地: だんじり祭りの地
投稿日時: 2008-03-11 16:02
引用:

セラフさんの書き込み (2008-03-11 14:29) より:
変数 = 割り込み命令文
変数 = 生存確認文


この「変数」はStringだと思いますが、StringBuilderクラスを使用してはどうでしょうか。

String オブジェクトを変更するように見えるメソッドは、実際には変更内容が反映された新しい String オブジェクトを返します。
↑この辺がオーバーフローを発生させていると眼力
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2008-03-11 16:07
引用:

セラフさんの書き込み (2008-03-11 14:29) より:
現象は、実行開始から20時間ほどでスタックオーバーフローが発生し、スレッドが落ちてしまうというもので、プログラム自体はWinodwsサービスとし作成してあります。


スタックオーバーフローはコールスタックがオーバーフローしているのでしょうか?すなわち、メソッド呼び出しが多重にネストしているのでしょうか?だとしたら、意図せず再帰呼び出しのようなことをしているのかもしれず、もしそうであれば複雑なグラフ探索などでないかぎり、プログラムの間違いであることがほとんどでしょう。
ソースコード中で再帰呼び出しになる可能性はあるのでしょうか?(まったくない、少しある、再帰を前提として作ってある、etc.)

それともデーターのスタックがオーバーフローしているのでしょうか?C/C++ ならばそういうこともあるのかもしれませんが、今はスタック領域をデーターに使うということはほとんどないため、これは少ないと思います。

スタックオーバーフローする少し手前で、プログラムの実行をブレーク(一時停止)した場合、呼び出し履歴は多重になってはいないのでしょうか?サービスということなのでデバッグが難しいかもしれませんが。ちなみにサービスでなければこのエラーにはならないのでしょうか?
indigo-x
大ベテラン
会議室デビュー日: 2008/02/21
投稿数: 207
お住まい・勤務地: 太陽の塔近く
投稿日時: 2008-03-11 16:11
そうですか、更にコメントアウト可能であればしてみてはどうですか?

スタックオーバーフローは考え難いですね。
(考えられるのはDLLImportとかして引数が多いとか?)

その他の対策案として

・最後の手段は、最小限なコードにしてアセンブリコードを確認する?
・C#orC++/CLIに書き直す(VB.NETとコンパイラーが違うので)
・C言語で書いてVB.NETから呼び出す等
・24時間稼動でなければ10時間毎にこっそりスレッド入替える
  (おそらく100msぐらいで入替え完了すると思います)

参考になればと思います。

スキルアップ/キャリアアップ(JOB@IT)