秒表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();
}
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();
}
}
}
说了这么多,最明显的答案是,事实上,你并没有在线程之间共享一个秒表,而是意外地为每个线程启动了一个新的秒表。。。