ループを使わない実行待ちをするには?


紅閃光  URL  2006-08-09 07:35:58  No: 132738

いまさら(しかたなく)VB6を始めてるものです。
主な目的としてハードウェア制御を行っています。

アクチュエータの起動信号をOUTしてから完了信号がINするまでの間、
待機する必要があります。

そこでDo〜LOOPを完了信号立つまでループさせて、
ループ内にDoEventsとタイムアウトチェックを行っています。

ところが上司に言わせるとループ待ちはマルチタスク環境においては下の下だそうです。(ビジーループがいくないのでしょうか?)

仮に起動した時点でルーチンを抜けておいて、完了信号でイベントを立てたとしても、どうやってメインフローを継続すればいいのでしょうか?
ステップ番号を持って別プロシージャを転々とする事は思いつきますが、視認性が著しく落ちてしまいます。

また、ループ内にsleepを入れてCPU使用率を落す方法はありますが、
RS-232Cでデータリンクを行うのにOnCommイベントを使っているのでsleep中はイベントが立たなくなるので使えません。

①ループを使わない待機状態かつ読み易い構造のプログラム
②イベントを画さない形でのビジーループ緩和方法

この2件でなにかエレガンスな方法は無いものでしょうか?
いいメソッドをお持ちの方がおいでなら御教授願います。


オショウ  2006-08-09 10:24:06  No: 132739

PIOなりDIOのボードを使って、ポートをIN/OUTして行って
おられるようですが、ボードのメーカーやドライバー・ActiveXで
信号の変化によっては、割り込み処理(イベント)が可能なもの
もあります。

今お使いのボードでは、IN/OUTしかできないようでしたら、VB6
のみでは無理です。C++等でActiveX作って、VB6に貼り付ける
ことになります。

『下の下』と言った人に、IN/OUTしかできないドライバーでエレガント
なソフトをお手本として作ってもらうましょう!それもVB6のみで!

以上。


我龍院忠太  2006-08-09 16:32:29  No: 132740

要するにポートをポーリングする為の
VB用の精密タイマーがほしいと言うことですね。
たとえば
CONTEC API-TIMER(W32)  
http://www.contec.com.tw/product/special/apipac/#TIMER
精度1 ±200μ  msec
なんかは結構使えます。

その他、どの位の精度が必要かにもよりますが、
Do〜Loopの中にSleep(1)を入れます。
これだとCPUの使用率を5%以下に落とし、RS-232Cの通信などには
殆ど影響が出ません。


我龍院忠太  2006-08-09 16:40:11  No: 132741

訂正
×精度1 ±200μ  msec
〇精度  1m ± 200μ sec
謝!


紅閃光  URL  2006-08-10 16:51:34  No: 132742

貴重な意見ありがとう(^▽^)ゴザイマース

すいません。
msecでの精密さがほしいいのではなくって、
もっとプログラム構造をどのようにしたらいいのかが知りたいというのが①です。
イベントが可能だったときにどのような構造にすればいいのかなと。

件の上司はC畑な人なので、イベントに対応するならActiveXを作ってもらおうかと思っています。
(´▽`*)アハハ 

②にはマルチメディアタイマーを使う方法があると聞きましたのでそこは調べて見ます。
ところで、sleepを使うとイベントは、無視されるのですか?
それとも遅れるだけなのですか?
sleep(1)ではなくsleep(0)としたときになにかまずい事ってあるんですかね?

昔、ポケコンでクラシックBASICをやっていたせいもあり、
なかなか脳がついてきません。(ノ∀`)ペチ


オショウ  2006-08-10 17:59:05  No: 132743

まず根本的な話、DIOやPIOのボードはお使い?
メーカーは?型式は?

メーカーからAvtiveX出ていませんか?

無いなら、C(MFC)でActiveX作るのがいいですが、C言語でも
どのみちループしてポートをリードしないことにはできませんヨ!

デバドラ作るのなら、イベント化できますがネ〜

それと、VBの場合、Sleep入れると全ての機能が停止します。よって
その間に発生したイベントは全て取りこぼすことになります。

以上。


我龍院忠太  2006-08-11 03:37:00  No: 132744

>msecでの精密さがほしいいのではなくって、
>もっとプログラム構造をどのようにしたらいいのかが知りたいというのが1です。
ポーリングは本来タイマーで行いますが、VBのTimerはせいぜい分解能が50msecです、
これで間に合うポーリングならこれを使えば良いでしょう。
大概の場合はこれでは分解能が足りません、そこで精密タイマーを使います。
もちろんCでActiveXを作る方法も有りますが、CでActiveXを作ることが出来る人は
ここで質問しないんじゃないかな思ったので.....

>イベントが可能だったときにどのような構造にすればいいのかなと。
これはどのような意味でしょうか、VBはもともとイベントドリブンが基本です。
ポートを監視していて変化が有った時に割り込みをかけてくるソフトはたくさん有ります。
ただしこの様なソフトは大抵、割り込みの中でブレークをかけるとスレッドがハングします。
従って割り込み処理の中にほとんどのコードを書く必要が有る場合は、デバッグがかなり
やりにくくなります。まあこれはこれで何とかごまかす手はあるのですが...

>2、にはマルチメディアタイマーを使う方法があると聞きましたのでそこは調べて見ます。
マルチメディアタイマーはVB5までは使えましたが、VB6のネイティブコンパイラー
では殆ど使用出来ません、P-Codeコンパイルを使うか、VB5以前のバージョンを使うかです。

>sleep(1)ではなくsleep(0)としたときになにかまずい事ってあるんですかね?
その答えもHelpに書かれています。
Sleepを入れるのは、他のスレッドに処理を回したい為ではなく、CPUの使用率を下げたいためですよね。

それと1番最初の質問ですが
>RS-232Cでデータリンクを行うのにOnCommイベントを使っているので
>sleep中はイベントが立たなくなるので使えません。
RS-232Cの速度を考えると、Sleep(1)で問題が起きるとは考えられません、RS-232C
はバッファを持っていますからね。
そもそもWindowsの画面上で自分のスレッドでも他のスレッドでもそのウインドウを
掴んで引き回すと、Sleep(10)以上のサスペンド状態が起きます。
従ってこれで問題が起きるようだと、画面固定、ネットワークの接続無しなどの
対策が必要になります。

>ところで、sleepを使うとイベントは、無視されるのですか?
>それとも遅れるだけなのですか?
答えはSleepのHelpに書かれています。
The Sleep function suspends the execution of the current thread for a specified interval. 
つまりSleep中はそのスレッドのイベントは起きません。

>それと、VBの場合、Sleep入れると全ての機能が停止します。よって
>その間に発生したイベントは全て取りこぼすことになります。
えーと、これどのような意味でしょう、全ての機能が停止してるとイベントが起きませんが。
I/Oの変化速度が1msec以下の場合(Sleep(1)の場合2msec位になるかな)この変化は感知出来ません、
尤もI/Oの変化速度が1msec以下の場合はVBでの無理ですね、というかソフトでの処理は
無理ぽいですね。

長いSleepを入れたい場合はHelpに有るようにMsgWaitForMultipleObjectsを使います、
ただし分解能は未定です。

Cで作る場合ActiveXを作らなくても、DLLで作る方法も有ります、この場合はポートをポーリング
していて、ポートに変化が有ったら、SendMessageでVBに送ります、これだと殆どCの知識が無くても
出来ます。ただしポーリングが早くなりすぎて、CPUの使用率が上がる為、そのループにSleepを入れる
ことになります。


紅閃光  2006-08-11 07:02:13  No: 132745

あ、マルチメディアタイマーと書いたのは寝ぼけてたのかな。MsgWaitForMultipleObjects ですです。
o /rz 誤爆スマソ

我龍院忠太さま、オショウさま助言ありがとうございます。

個人的にはMsgWaitForMultipleObjectsでコーヒーが出来るのを待つかんじが一番しっくりきます。
今知りたいのはイベントを立てる方法ではなく、
イベントが立ったあとで動作させる方法が発想できないのです。
凝り固まったわたしの脳ではちょっと想像がつかないので教えてください。

先に言います。長文ごめんなさい。

とりあえず現在のプログラムの概要

sub ①ボタンclick
    call ⑤メインルーチン
sub end

sub ②インターバルタイマ
    定期的にシリアルでアクチュエータにデータ送信要求コマンド
sub end

sub ③oncommイベント
    call ④電文結合チェック判断ルーチン
sub end

sub ④電文結合チェック判断
    do〜Loopで末尾文字まで1文字入力結合
    データ受信のときサムチェック&受信データをフラグ化
sub end

sub ⑤メインルーチン
    フラグチェック
    動作A開始指令
    動作B開始指令
    do〜Loop動作A完了フラグチェック
    動作C開始指令 withパラメータ①
    do〜Loop動作C完了フラグチェック
    do〜Loop動作B完了フラグチェック
    動作D開始指令
    do〜Loop動作D完了フラグチェック
    動作C開始指令 withパラメータ②
    do〜Loop動作C完了フラグチェック
    動作E開始指令
    do〜Loop動作E完了フラグチェック
    データ処理
    call ファイル保存
sub end

sub ⑥ファイル保存
    保存処理
sub end

sub ⑦エラーチェック
    アクチュエータのエラーチェック
    エラーのときの再起処理(エラー無しでexit sub)
    do〜Loop再起完了状態チェック
sub end

当然do〜Loop中にはDoEventsが入っています。
また⑤のルーチンのLoop内では⑦をcallしています。
実際にはシリアル通信×2、GI-IB、DIO、AIOなどくっつきますのでごちゃごちゃしているのですが。

このようなプログラムのときに、
仮にアクチュエータのフラグ変化をイベント化したとすると、
⑤のメインルーチンはどのような形になるのでしょうか。
(シリアル通信はOnCommEventを使いますし、DIO、AIOはメーカーActiveXでイベントが起こせるようです。)

無処理の状態からイベントで動作を開始すると言うことは、メインルーチンがいくつかのサブルーチンに分割されて縁が切れてしまうのですよね?
そうすると動作C完了イベントが起きたとして、
次は動作Dを行うのかそれとも動作Eを行うのかはどうやって区別しましょう。

また動作Bの完了と動作Dの完了のタイミングが逆になることを許容するためには?
ちなみに一つ一つの動作完了を待てよ、との意見もあるかと思いますが、
稼働率を上げるためにはシーケンシャルな処理をしてる暇がないもので・・・

あるいは動作する必要が無かったときは開始指令を出さないので、
そうすると完了イベントは起きないので次の動作につなぐ方法が無くなります。
単純に考えるとこのようなプログラムこそマルチタスクっぽい処理が真価を発揮するような・・・

こんなことを考えているとイベントでつなぐ方法が気になって気になって仕方がありません。

はるかな昔、ポケコンでクラシックBASICをやっていたせいもあり、
なかなか現代(?)のプログラミング手法に脳がついてきません。(ノ∀`)ペチ

現代のプログラマーの脳をお貸しください。


K.J.K.  2006-08-11 21:17:16  No: 132746

# 全角・半角文字の使い分けは適切に。
# 丸数字は機種依存文字ですので、ネット上での使用は推奨されません。
# (まぁ、Shift-JISなら表示はされるけど。)

ハードから信号が送られてきたら、例えば、
シリアル通信のコントロールではOnCommEventイベントが発生し、
他のハードでもコントロールがそういうイベントを発生させる、
というのならば、その段階で、貴方の上司が言っている、
「ループ待ちはマルチタスク環境においては下の下」
を避ける機能が備わっている、ということです。

つまり、貴方の上司は最初からその点がわかっているので、
貴方に構造を見直せ、と言っていることになります。

要するに、Doループなどを使わなくても、適切なイベント
プロシージャで適切な処理をするだけで良い、ということです。

でまぁ、まずは「状態遷移図」を書くことから始めてみては。
(5)のコードの多くは(3)に組み入れられるべきですよね。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加