0

現在、ストップウォッチをグローバル タイマーとして使用しています。メインスレッド、別のスレッド、およびイベントメソッドを実行しています。メイン スレッドが他のスレッドを起動し、イベント メソッドがイベントによってトリガーされます。どちらのメソッドもストップウォッチを呼び出して時間を取得します。問題は、時間が一貫していないということです: メインスレッドから: START REC AT 9282 STOp REC AT 19290

別のスレッドから: オーディオ 1 オーディオ 304 オーディオ 354 オーディオ 404 オーディオ 444 オーディオ 494 オーディオ 544 オーディオ 594

from イベントメソッド: video 4 video 5 video 29 video 61 video 97 video 129 video 161

9282 で録音を開始すると、ストップウォッチを呼び出す他の 2 つの関数のタイマーがゼロから開始される理由がわかりません。これはスレッド関連の問題ですか? どうすればこれを修正できますか? ありがとう

更新: * ** * ** * **

フレームを保存すると、次のように変更されました: long a = relogio.EllapseMilliseconds この値を出力すると、期待どおりに問題ありません。しかし、リストに保存されている値を出力すると、最初から値が表示されます。変でしょ?お手数をおかけして申し訳ありません。開始時刻を指定せずに印刷したため、すべてがゼロから開始されたように見えました。どうもありがとうございました。

メインスレッド

   private void Start_Recording_Click(object sender, RoutedEventArgs e)
    {

        rec_starting_time = relogio.ElapsedMilliseconds;
        Console.WriteLine("START REC AT " + rec_starting_time);
        write_stream.enableRecording();

        Thread a = new Thread(scheduleAudioVideoFramePicks);
        a.Start();

scheduleAudioVideoFramePicks - このスレッドは時間をカウントするだけなので、いつ停止するかがわかります

       //while....
      if (rec_starting_time + time_Actual > rec_starting_time+recording_time * 1000)//1000 - 1s = 1000ms
            {
                totalRecordingTimeElapsed = true;
                write_stream.disableRecording();
                Console.WriteLine("STOp REC AT " + relogio.ElapsedMilliseconds);
            }
     //end while
    lock (list_audio)
        {
        int b = 0;
        //print time of frames gathered
        foreach(AudioFrame item in list_audio){
            Console.WriteLine("audio " + (item.getTime() - rec_starting_time));
        }
        lock (list_video)
        {
        }
        foreach (VideoFrame item in list_video)
        {
             Console.WriteLine("video " + (item.getTime() - rec_starting_time));
        }
        }

私が時間を得る別のスレッド

     if (write_stream.isRecording())
            {

                list_audio.Enqueue(new AudioFrame(relogio.ElapsedMilliseconds, audioBuffer));

            }

イベントメソッド

             if (write_stream.isRecording())
                    {

                        list_video.Add(new VideoFrame(relogio.ElapsedMilliseconds, this.colorPixels));


                    }~

これが関連しているかどうかはわかりませんが、ストップウォッチをこのように開始します

  public MainWindow()

    {
        InitializeComponent();

        //some code

        this.relogio = new Stopwatch();
        relogio.Start();

    }
4

1 に答える 1

5

ストップウォッチは、特に 32 ビット プログラムの場合、スレッドセーフではありません。

これは、Windows API 呼び出しを使用しQueryPerformanceCounter()てプライベート long フィールドを更新します。32 ビット システムでは、別のスレッドが更新中に long 値を読み取ると、"torn read" が発生する可能性があります。

これを修正するには、ストップウォッチへのアクセスをロックする必要があります。

また、一部の古いシステムでは、異なるスレッドがQueryPerformanceCounter(). ドキュメントから:

マルチプロセッサ コンピュータでは、どのプロセッサが呼び出されるかは重要ではありません。ただし、基本入出力システム (BIOS) またはハードウェア アブストラクション レイヤー (HAL) のバグにより、異なるプロセッサでは異なる結果が得られる可能性があります。スレッドのプロセッサ アフィニティを指定するには、SetThreadAffinityMask 関数を使用します。

私自身、このバグに遭遇したことはありませんし、あまり一般的ではないと思います。

次のテスト プログラムでどのような結果が得られますか? ほとんどの場合、時間は値が増加するはずですが、スレッドが値を読み取った直後でキューに追加する前にスレッドが再スケジュールされるため、1 つまたは 2 つの順序が狂う可能性があります。

namespace Demo
{
    class Program
    {
        Stopwatch sw = Stopwatch.StartNew();

        object locker = new object();
        ConcurrentQueue<long> queue = new ConcurrentQueue<long>();
        Barrier barrier = new Barrier(9);

        void run()
        {
            Console.WriteLine("Starting");

            for (int i = 0; i < 8; ++i)
                Task.Run(()=>test());

            barrier.SignalAndWait(); // Make sure all threads start "simultaneously"
            Thread.Sleep(2000); // Plenty of time for all the threads to finish.

            Console.WriteLine("Stopped");

            foreach (var elapsed in queue)
                Console.WriteLine(elapsed);

            Console.ReadLine();
        }

        void test()
        {
            barrier.SignalAndWait(); // Make sure all threads start "simultaneously".

            for (int i = 0; i < 10; ++i)
                queue.Enqueue(elapsed());
        }

        long elapsed()
        {
            lock (locker)
            {
                return sw.ElapsedTicks;
            }
        }

        static void Main()
        {
            new Program().run();
        }
    }
}

そうは言っても、最も明白な答えは、実際にはスレッド間で単一のストップウォッチを共有しているのではなく、スレッドごとに新しいストップウォッチを誤って開始したことです...

于 2013-07-06T18:40:32.797 に答える