VB6 ランダムアクセスファイルで


セロ  2008-01-18 16:22:58  No: 138660  IP: 192.*.*.*

VB6 + Windows2003 Server にて1秒周期でランダムアクセスファイルへデータのロギングをするソフトを作成しています。
ファイルは1レコード=1秒という構造です。

1秒周期は・・・

Form_Load
   Timer1.Interval = 300
   Timer1.Enabled = True
End Sub

Private Sub Timer1_Timer
   Static BeforeDateTime As Date
   Dim DateTime
   
   DateTime = Now
   if BeforeDateTime<>DateTime Then
      '秒が変わったら

      Call Loging 'ファイル記録処理

      BeforeDateTime = DateTime
   End if

End Sub

・・・という感じで処理していますが、ここで問題が発生しておりす。

通常はSUBプロシージャ"Loging"の処理時間(Timer関数にて測定)は0.05秒くらいで問題ないのですが、まれに1.n秒かかってしまい、次回のタイマイベントの発生が1秒遅れてしまう事があります。(ファイルレコードの欠損が起こる)

ちなみにロギング中のファイルは、このプログラム以外からのアクセスはありません。
このプログラム以外には、ORACLE10gがインストールされております。

色々考えてロジックを見直したりしてはみたのですが、解決にいたりません。。。
他のPC等がアクセスしてもいないのに、ランダムアクセスファイルへのアクセスに遅延が発生するような事はあるのでしょうか?

何か良いアドバイスがありましたら、よろしくお願いいたします。

編集 削除
セロ  2008-01-18 16:24:00  No: 138661  IP: 192.*.*.*

訂正

   Dim DateTime →    Dim DateTime As Date

編集 削除
我龍院  2008-01-18 18:22:19  No: 138662  IP: 192.*.*.*

「1.n秒」これは1秒以上と言う意味かな。
とりあえずSetThreadPriorityでスレッドの優先順位を上げてみましょうか。

ネットワークにブロードキャストが流れると一瞬CPUの負荷が増える事があります。

 Timer1.Interval = 300
 if BeforeDateTime<>DateTime Then
これはちょっとラフじゃないかな。
   Dim BeforeTime As Long
    Do
        If Abs(timeGetTime - BeforeDateTime) >= 1000 Then
            'do something
            BeforeTime = timeGetTime
        End If
        Sleep (1)
        DoEvents
    Loop
こんなのでやってみるとか。

編集 削除
特攻隊長まるるう  2008-01-18 19:35:21  No: 138663  IP: 192.*.*.*

何を問題だと思って質問していますか?

同じ処理(ファイル記録処理)が0.05秒で終わったり、
1秒以上かかったりすることを疑問に思っているなら、
Loging の中身をまず確認すべきでは?

そうなると、サンプルコードも関係ない内容ですよね?
タイマーだとかは関係なく、ファイル記録処理の前後で
処理時間を計らないと意味がないでしょう?

まぁ、我龍院さんのアドバイス通り
> Timer1.Interval = 300
> if BeforeDateTime<>DateTime Then
の判定がザルで、Loging を正しく呼べてないのだけかも
しれませんが。

編集 削除
セロ  2008-01-18 20:31:42  No: 138664  IP: 192.*.*.*

>我龍院さん、特攻隊長まるるう

アドバイスありがとうございます。

我龍院さん、SetThreadPriorityでスレッドの優先順位を上げるという件ですが、VBでできました?
以前、別件にて試そうと思った機会があったのですが、VBでは無理だという情報があり、断念した事がありまして・・・
だからよくわかんないのです(^◇^;)
先ほどネットで調べてはみたのですが、みつかりませんでした。
どこか参考になるようなサイトをご存じでしたら教えていただけますでしょうか?



特攻隊長まるるうさん
> Loging の中身をまず確認すべきでは?
↑のサンプルコードですが、抜けがありました。
実は、ある機器の専用ボードのAPIを使用して数百点のデータを配列に取得後に、Loging がコールされるのですが、Logingでは、以下のような処理をしています。


Public Sub Loging()
   Data.DateTime=Now

   For i=0 to 300
      配列(i)=配列(i)・・・データの加工処理
      Data.Dat(i)=配列(i)
   Next i

   n=FreeFile
   Open FileName For Random Access Write Shared As #n Len=Len(Data)
   Rec=書き込みレコード算出(1秒1レコード)
   Put #n,Rec,Data
   Close #n
End Sub

※変数の宣言などは省略しております


> if BeforeDateTime<>DateTime Then
> の判定がザルで、Loging を正しく呼べてないのだけかも
> しれませんが。
試験段階なもので、確かにラフ過ぎますが、きちんと処理されております。

最終的にはtimeGetTimeを使って精度はあげるつもりです。
ご指摘ありがとうございます。

 
Openの所用時間、Putの所用時間、Closeの所用時間など細かな確認はしておりませんが、やってみようと思います。

編集 削除
我龍院  2008-01-18 21:56:27  No: 138665  IP: 192.*.*.*

>以前、別件にて試そうと思った機会があったのですが、VBでは無理だという情報があり、断念した事がありまして・・・
何故無理だと書いてありましたか?

Const THREAD_BASE_PRIORITY_MIN = -2
Const THREAD_BASE_PRIORITY_MAX = 2
Const NORMAL_PRIORITY_CLASS = &H20
Const REALTIME_PRIORITY_CLASS = &H100

Private Declare Function GetCurrentThread Lib "kernel32" () As Long
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long

Private Declare Function SetThreadPriority Lib "kernel32" _
(ByVal hThread As Long, ByVal nPriority As Long) As Long

Private Declare Function SetPriorityClass Lib "kernel32" _
(ByVal hProcess As Long, ByVal dwPriorityClass As Long) As Long

Private Declare Function GetThreadPriority Lib "kernel32" _
(ByVal hThread As Long) As Long

Private Declare Function GetPriorityClass Lib "kernel32" _
(ByVal hProcess As Long) As Long


Private Sub Form_Load()
    Dim hThread As Long
    Dim hProcess As Long
    Dim Ret As Long
    
    hThread = GetCurrentThread
    hProcess = GetCurrentProcess
    
    Ret = SetThreadPriority(hThread, THREAD_BASE_PRIORITY_MIN)
    Ret = SetPriorityClass(hProcess, NORMAL_PRIORITY_CLASS)
    Debug.Print "低優先のスレッド設定:" & GetThreadPriority(hThread)
    Debug.Print "低優先のクラス設定:" & GetPriorityClass(hProcess)
    
    Ret = SetThreadPriority(hThread, THREAD_BASE_PRIORITY_MAX)
    Ret = SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS)
    Debug.Print "高優先のスレッド設定:" & GetThreadPriority(hThread)
    Debug.Print "高優先のクラス設定:" & GetPriorityClass(hProcess)
End Sub
これで、特に問題は無いと思われますが。

>特攻隊長まるるう   さん
以前Windows2000をリアルタイムOSとして使用したことがありました、100msecに一回
IOを読んでその値をファイルに書き込むもので、その処理は時間に依って変わるものではなく、
ほんの10msec以下の時間に処理されるものでしたので、当然のことながら、殆どの場合正常に動作
していましたが、一日に2回ほど処理をこぼす事がありました。
原因究明にかなり時間が掛かりましたが、結局原因はネットワーク上のコンピューターの電源の
入り切り時に大量のブロードキャストが流れて、これが原因でした、まあ今回のトラブルも、
これと似てるかなと思って書き込んだわけです。
これはネットワークのコネクタを抜いて見るとすぐにわかるわけです。

編集 削除
セロ  2008-01-19 09:39:36  No: 138666  IP: 192.*.*.*

●補足関連
プログラムにトラップを張って、昨夜放置しておいてみましたところ、問題のポイントが判明しました。

Public Sub Loging()
   Data.DateTime=Now

   For i=0 to 300
      配列(i)=配列(i)・・・データの加工処理
      Data.Dat(i)=配列(i)
   Next i

   n=FreeFile
   Open FileName For Random Access Write Shared As #n Len=Len(Data)
   Rec=書き込みレコード算出(1秒1レコード)
   Put #n,Rec,Data
   Close #n
End Sub

↑のサンプルで言うとPutが1.796875秒ほどかかっておりました。
当然ながら常時はほとんどゼロ秒ですが・・・

以前に我龍院さんが経験された内容に近いと思います。
開発中のシステムであり、ネットワークにてパソコンが3台接続されておりますが、電源の入り切りもなく、クライアントPC上では何のソフトも動作しておりません。
また、以前に何度も同様のシステムを作っておりますが、今回の初めて「遅延」に遭遇いたしましたので、対策に困っております。
本体はDELLサーバーで、RAID5(500GB×3台構成)です。
ちなみに、同じソフトをクライアントPCでも動作させてみましたが、そちらは今のところ遅延が発生しておりません・・・
※クライアントPCで動作させたプログラムには、機器と接続する専用ボードがないので、専用のAPIの箇所はコメントアウトしております。また、ORACLEもインストールされておりません。

新品サーバーなので疑いたくはないですが、HDD(もしくは関連コントローラ)の故障なども考えさせられてしまいますので、近いうちに診断ツールなどで診断してみようかなと思っております。


>我龍院さん
VBによるスレッドの優先順位の設定のサンプルありがとうございます。
試してみようと思います。

編集 削除