Timerじゃ遅い

タグの編集
投稿者 ENIAC  (社会人) 投稿日時 2009/11/8 02:23:16
質問です。
題名の通りですがTimerの1000分の一秒ごとにイベントを起こすのでは遅いです。
もっと1万分の一秒ごとに、等は無理でしょうか?

あるていど正確さも要求したいのでよろしくお願いいたします。
投稿者 ENIAC  (社会人) 投稿日時 2009/11/8 02:23:55
連投すみません^^;
環境はVB2008です。
投稿者 neptune  (社会人) 投稿日時 2009/11/8 02:58:53
>もっと1万分の一秒ごとに、等は無理でしょうか?
は恐らく無理です。

以前からこの類の質問はありますが、Mutimedia Timer API でも、数ms~
その他のAPIでは10~20ms程度がwindowsでは限界らしいですよ。
FormのTimerコントロールは更に悪い。

ここまで出てきたwordで適当にググって見て下さい。

#そんな高い精度の使い道を書いた方が識者から目的に合った良いアドバイスが受けられます。
投稿者 (削除されました)  () 投稿日時 2009/11/8 03:04:10
(削除されました)
投稿者 葉月  (社会人) 投稿日時 2009/11/8 10:11:03
用途がわからないので憶測な解答になります。
そこまでの精度になるとタイマーを使わずに、
ループさせて条件がきたら抜けるような仕組みにする手もあると思います。
ただこの場合は、ループを抜けるまで操作不可になります。
操作を可能にするならマルチスレッドにする必要があります。

ただ、マルチスレッドと併用なら他の手を考えた方がいいかもしれません。
クロススレッドの問題などがあるためです。
デリゲートと各コントロールにあるInvokeRequiredプロパティを使って回
避する手段はありますが、私はマルチスレッドを小規模なツールでしか使
いません。
投稿者 ENIAC  (社会人) 投稿日時 2009/11/8 22:29:36
ありがとうございます。
調べてみましたが難しいですね・・・;;

マルチスレットすらわからない状態なのでもう少し勉強してきます<(_ _)>
投稿者 葉月  (社会人) 投稿日時 2009/11/10 07:27:56
レスを見ますと、マルチスレッドにする必要があるようですね。
スレッドの説明とかは、?と感じてしまうかも知れません。
説明だけなのも酷なので簡単なサンプルを作りました。

サンプルを掲載する前に、ざっくりとマルチスレッドの注意点を述べます。
マルチスレッドを行う場合には、いくつかの注意があります。
例えば、フォームコントロールは複数のスレッドからへのアクセスが考慮されていません。
フォームコントロールを異なるスレッドからの操作があった場合、マーシャリングを行う必要があります。
(VS2005から、コントロールへの異なるスレッドから操作があった場合に例外が出ます)
適切にマーシャリングを行うために、デリゲートを使用してInvoke経由でアクセスを行います。
マーシャリングが必要か判定を行うために、InvokeRequiredプロパティを使用します。

各サイトの説明を理解するのも大事でですが、実際にコードを記述し、
動かしながら見た方が納得しやすいと思います。
コードを見ることで、マルチスレッドを敬遠したい理由の一端が見えてきます。
悪いところばかり上げましたが、バックグラウンドで処理を並列に行う時などには役立ちます。

■参考リンク
http://www.atmarkit.co.jp/fdotnet/vblab/appqa_06/appqa_06_01.html
http://www.atmarkit.co.jp/fdotnet/mthread/mthread02/mthread02_03.html
投稿者 葉月  (社会人) 投稿日時 2009/11/10 07:31:41
マルチスレッドのサンプルです。
Hoge:<数字>
だけをループして表示します。
Button2が押されると、Lable1に終了が表示されて処理が終わります。

フォームには、以下のコントロールを配置してください。
Label×1
Button×2


■サンプル
Public Class Form1

#Region "フィールド"

    ' マルチスレッド用に使うdelegate 
    Private Delegate Sub multi()
    Private thread As multi
    ' クロススレッド対策に使うdelegate 
    Private Delegate Sub crossThreadEvasion()
    ' Hogeクラスを呼び出すインスタンス 
    Private objHoge As Hoge

#End Region


    Public Sub New()
        InitializeComponent()
        objHoge = New Hoge()
    End Sub

    Private Sub Form1_Load(ByVal sender As ObjectByVal e As EventArgs)
        Me.Label1.Text = String.Empty
        Me.Button2.Enabled = False
    End Sub

    ' 処理を開始 
    Private Sub Button1_Click(ByVal sender As ObjectByVal e As EventArgs) Handles Button1.Click
        Me.Button1.Enabled = False
        Me.Button2.Enabled = True

        thread = New multi(AddressOf BackGroundConnect)

        ' 別スレッドで処理を開始し、BackGroundConnectの処理が終了したらEndShowが呼ばれます。 
        ' nullはEndShow(ByVal ar As IAsyncResult)メソッドの引数。 
        ' 平たく言うと、非同期処理で同期を取りたい時に利用します。              
        thread.BeginInvoke(New AsyncCallback(AddressOf EndShow), Nothing)
    End Sub

    ''' <summary> 
    ''' HogeShowを呼び出す。 
    ''' このメソッドは、別スレッドから処理されます。 
    ''' </summary> 
    Private Sub BackGroundConnect()
        objHoge.HogeShow()
    End Sub

    ' 処理を終了 
    Private Sub Button2_Click(ByVal sender As ObjectByVal e As EventArgs) Handles Button2.Click
        objHoge.IsEndLoop = True
    End Sub


#Region "終了処理"

    ''' <summary> 
    ''' 終了処理 
    ''' </summary> 
    Private Sub EndShow()
        Me.Label1.Text = "処理を終了します。"
        Me.Button1.Enabled = True
        Me.Button2.Enabled = False
        objHoge.IsEndLoop = False
    End Sub

    ''' <summary> 
    ''' クロススレッド対策用。 
    ''' endShowメソッドをデリゲート経由でアクセスする。 
    ''' </summary> 
    Private Sub EndShowInvoke()
        Me.EndShow()
    End Sub

    ''' <summary> 
    ''' 終了処理のマーシャリング 
    ''' </summary> 
    ''' <param name="ar">平たく言うと、非同期処理で同期を取りたい時に利用</param> 
    Private Sub EndShow(ByVal ar As IAsyncResult)
        ' Invokeの処理が必要か? 
        If Me.Label1.InvokeRequired Then
            Dim d As New crossThreadEvasion(AddressOf EndShowInvoke)
            Me.Invoke(d)
        Else
            Me.EndShow()
        End If
    End Sub

#End Region

End Class


投稿者 葉月  (社会人) 投稿日時 2009/11/10 07:33:49
'別クラス 
Class Hoge

    ' 終了処理を行うか判定 
    Private flgEndLoop As Boolean

    ''' <summary> 
    ''' 終了処理を行うか? 
    ''' </summary> 
    Public Property IsEndLoop() As Boolean
        Private Get
            Return Me.flgEndLoop
        End Get
        Set(ByVal value As Boolean)
            Me.flgEndLoop = value
        End Set
    End Property



    ''' <summary> 
    ''' ひたすらHogeを表示する。 
    ''' </summary> 
    Public Sub HogeShow()
        ' カウント 
        Dim sCount As Short = 0

        While True
            If Not IsEndLoop Then
                Console.WriteLine("Hoge:" & sCount)
                sCount += 1
                System.Threading.Thread.Sleep(100)
            Else
                Return
            End If
        End While
    End Sub


End Class
投稿者 ENIAC  (社会人) 投稿日時 2009/11/10 22:27:29
詳しくありがとうございます。

Mutimedia Timer API も調べたのですがエラーで使えませんでした。


ですのでマルチスレッドに法でやってみたいと思います。
解説本が少しマルチスレッドのことに触れていたのでそれを見ながら出してくださったコードをいじってみたいと思います。

ところでマルチスレッドとは
While (1)

End While

のように無限ループに入るとソフトが応答しなくなるが別スレッドで無限ループをするとそのまま処理が続けられる、ということであっているのでしょうか?
投稿者 ENIAC  (社会人) 投稿日時 2009/11/10 23:18:21
BackgroundWorkerコントロールを使い、無事目的のことができました!

マイコンを使ってオシロスコープを作っていたのですがなかなかきれいにいかないものですね^^;

このたびはありがとうございました。またよろしくお願いいたします。
投稿者 葉月  (社会人) 投稿日時 2009/11/11 04:56:24
私がBackgroundWorkerを使うときは、状態推移(ポンプ)の時に利用しています。
 MSDNでも、その部分が特徴的に記述されています。
 何はともあれ、目的の操作ができたようでなによりです。

>>>無限ループに入るとソフトが応答しなくなるが別スレッドで無限ループをするとそのまま処理が続けられる、ということであっているのでしょうか? 
 だいたいその通りです。念のためにサンプルの説明をします。
 通常、HogeShow()で行っている部分はシングルスレッドだと、
IsEndLoopプロパティを変更する術がないので無限ループに入ります。
 別スレッドとしてHogeShow()を動かすことで、Formの操作が可能になります。
 今回のサンプルでは、button2を押すことにより、IsEndLoopの状態が変わり操作が終わります。
 もちろん、終了判定を入れなければ、操作はできますが処理は無限ループするので終わりません。
投稿者 KOBA789  (中学生) 投稿日時 2009/11/11 08:41:49
>>無限ループに入るとソフトが応答しなくなるが別スレッドで無限ループをするとそのまま処理が続けられる、ということであっているのでしょうか?
表ですべて作業をやると応答がなくなりフリーズ状態になるけど、
裏で処理すれば表はフリーズしない。
受付係が事務処理やってると話しかけられないけど、裏のほうでやっていれば受付は暇でいられる。
だいたいこんな感じでしょうか。

#無駄レスだったらすみません。
投稿者 るしぇ  (社会人) 投稿日時 2009/11/13 00:10:30
別スレッドにしても、結局同じCPUを使うのだから、
無限に計算すればCPUをたくさん使って他の処理が
重くなります。

葉月さんのサンプルではSleep(100)で休憩を入れていますね。
これを削除すると限界まで処理しようするのでCPU使用率が
跳ね上がります。

> 無限ループに入るとソフトが応答しなくなるが別スレッドで無限ループを
> するとそのまま処理が続けられる、ということであっているのでしょうか? 
無限ループの処理に問題があれば、解決には至りません。
> 受付係が事務処理やってると話しかけられないけど、
> 裏のほうでやっていれば受付は暇でいられる。
受付係が事務を同じAさんが1人でやっていれば、裏で事務やってる間は
受付に誰も居ないので受付できないです。

結局のところ、目的とか、実行している処理内容とか、状況まで
考慮しないとハッキリとした結論が出せないことは最初のレスから
指摘を受けているけど、会話ができていないので解決しようがない
でしょうね。
投稿者 オショウ  (社会人) 投稿日時 2009/11/30 20:56:49
FA関係のソフト屋やってますので、ちょっと突っ込んでみます。

※ 時間が経過してしまっているので、すいません・・・

まず、タイマーイベントを起こしたいとのことですが、技術的に可能か不可能か
と言えば可能です。ですが、デバイスドライバー側から見た場合の時間保障とし
ては、実際には、1msが限界で、0.1msや0.01msは一般的にはできません。

次に.NET Frameworkを使って・・・となると、やはり1msが限界です。

※ 1msが保障されているわけではありません。
  DDK的には、保障されているらしいですが。

一般的では無い方法は、C言語でバリバリ書くことになります。

では、そのタイマーイベントの折、何をするのでしょうか?
1msや0.1ms以内で終わる処理を行う前提でしょうか?

高精度タイマーについて・・・
PCが持っている内部的タイマーを使用することは、API的には問題はありま
せんが、.NETにはそれだけの精度のタイマーイベントは要求できません。
では、不可能か?となるのですが、最悪はPCIバスにタイマーボード等を突
っ込んで、タイマーイベントを発生させ、そのイベントを受信して行うのです
が、1ms未満となると、やはり.NETでは無理があります。
コールバック関数を定義して、タイマーライブラリ側からユーザーアプリ側の
関数を呼び出させ処理を行うことになります。

タイマーイベントと言うよりは、割り込み処理と言った方がいいでしょう~

0.2ms割り込みで、500時間とか連続稼働させたことあります。
完全にC言語でバリバリ書きましたが・・・

昨今は・・・
WinDriverと言うものがあり、デバイスドライバーはDDKを使って製作した
ものですが、これを使用すると、ユーザーモードアプリレベルでデバドラレベ
ルの機能のものが作れます。

http://www.xlsoft.com/jp/products/windriver/windriver_windows.html

この場合は、開発環境として・・・
C、C#、VB.NET、VB 6.0 または Delphi をサポートする開発環境
とありますので、.NET使えますネ!

しかしながら、使えるからと言って、無茶なコードを書くと、OSごと落ちて
しまうことは当然ありますので、注意が必要です。

要望されることは、恐らく可能な話だと思いますが、サイクリックに発生する
タイマーや割り込み処理中に、どの程度の処理を行いたいのか?もしくは、何
をしたいのかが解りませんので、そういう内容の提示があれば、もっと具体的
なコメントも可能かと思います。

※ こちらの掲示板では、かなり高度な話になってしまいました・・・

  簡単に高機能なことがしたい・・・
  と言うのであれば、WinDriver等有償商品をお使いになることを検討され
  るのがよいように思います。

※ 余談ながら・・・
  話はそれますが・・・

  InTime
  http://www.mnc.co.jp/intime/

  こんなものもあります。
  昨今のハイスペックPCなら特に問題は無いでしょう~
  (マルチCPU・マルチコア環境が必要です)

以上。