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

我目前正在使用秒表作为全球计时器。 我有主线程运行,另一个线程和事件方法。 主线程启动另一个线程,事件方法由事件触发。 两种方法都会调用秒表并获得时间。 事情是,时间不一致:从主线程:START REC AT 9282 STOp REC AT 19290

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

来自事件方法:video4video5video29video61video97video129video161

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

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

当我保存我的帧时,我改为: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(); } 

秒表不是线程安全的,特别是对于32位程序。

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

要解决这个问题,你必须锁定对秒表的访问。

还要注意,一些较旧的系统存在错误,其中可以从调用QueryPerformanceCounter()不同线程返回不一致的值。 从文档:

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

我自己从未遇到过这个错误,我认为这种情况并不常见。

您通过以下测试程序获得了什么结果? 时间应该大部分都在增加,但是你可能会因为他们的线程在读取值之后以及在将它们添加到队列之前重新安排而导致一个或两个乱序。

 namespace Demo { class Program { Stopwatch sw = Stopwatch.StartNew(); object locker = new object(); ConcurrentQueue queue = new ConcurrentQueue(); 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(); } } } 

说了这么多,最明显的答案是,事实上你并没有在线程之间共享一个秒表,而是你不小心为每个线程开了一个新的秒表......