秒表c在不同的线程中表现不同

本文关键字:线程 秒表 | 更新日期: 2023-09-27 18:21:13

我目前正在使用秒表作为全局计时器。我有一个正在运行的主线程、另一个线程和一个事件方法。主线程启动另一个线程,事件方法由事件触发。这两种方法都将调用秒表并获取其时间。问题是,时代并不一致:来自主线程:9282开始RECSTOp REC AT 19290

从另一个线程:音频1音频304音频354音频404音频444音频494音频544音频594

from事件方法:视频4视频5视频29视频61视频97视频129视频161

我不明白为什么如果我在9282开始我的rec,那么调用秒表的另外两个函数会有从零开始的计时器?这是与线程相关的问题吗?我该怎么解决这个问题?感谢

更新:

保存帧时,我更改为:long a=重新登录。Ellapse毫秒正如预期的那样,我打印出了这个值和它的ok。但是,当我打印存储在列表中的值时,它们从一开始就存在。奇怪吧?很抱歉给我带来了麻烦,我没有打印开始时间,这就是为什么它们似乎都是从零开始的!非常感谢和抱歉!

主线程

   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();
    }

秒表c在不同的线程中表现不同

Stopwatch不是线程安全的,尤其是对于32位程序。

它使用Windows API调用QueryPerformanceCounter()来更新私有长字段。在32位系统上,当一个线程读取长值,而另一个线程正在更新它时,你可能会得到一个"撕裂读取"

要解决这个问题,你必须在通往秒表的通道周围上锁。

还要注意的是,在一些较旧的系统中,存在错误,可能会从调用QueryPerformanceCounter()的不同线程返回不一致的值。来自文件:

在多处理器计算机上,调用哪个处理器应该无关紧要。然而,由于基本输入/输出系统(BIOS)或硬件抽象层(HAL)中的错误,您可能会在不同的处理器上获得不同的结果。要指定线程的处理器相关性,请使用SetThreadAffinityMask函数。

我自己从来没有遇到过这个bug,我认为它不是很常见。

以下测试程序的结果如何?这些时间的值应该大部分都在增加,但您很可能会出现一两个不正常的情况,因为它们的线程在读取值之后和将值添加到队列之前会被重新调度。

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();
        }
    }
}

说了这么多,最明显的答案是,事实上,你并没有在线程之间共享一个秒表,而是意外地为每个线程启动了一个新的秒表。。。