我有C#代码,它生成带时间戳的事件。它们还获得序列号,因此可以严格排序(甚至跨线程)。这些方面的东西:
private static int NextInSequence = 0;
private int Sequence;
private DateTime TimeStamp;
private void CaptureState()
{
this.TimeStamp = DateTime.UtcNow;
this.Sequence = Interlocked.Increment(ref NextInSequence);
}
理想情况下,只需要时间戳将它们按正确的顺序排列,但它可以在DateTime.UtcNow的单个增量的分辨率内生成许多事件。所以当时间戳相等时,Sequence用于排序。
在我将C ++引入混音之前,这些都不是问题。我将代码移植到C ++,并且该代码是从C#代码PInvoked,因此来自两者的事件混合在一起。他们以相同的方式计算时间戳,但我发现当C ++代码生成与C#代码具有相同时间戳的事件时,我遇到了问题。所有C ++的东西都是有序的,C#也是有序的,但它们的交互是乱序的。
因此,如果在线程上以实际顺序发生事件:
Managed event => Unmanaged event => Unmanaged event => Managed event
它可能会像这样排序:
Managed event => Managed event => Unmanaged event => Unmanaged event
线程之间的交互顺序并不重要,因为确保在一个线程上发生的所有事情都保持与创建它的顺序相同。
我想如果我使用更高分辨率的时间戳,那么每个事件都会获得一个独特的时间戳,我就会开展业务。所以下一次尝试使用QueryPerformanceCounter,类似这样(不包括错误检查等):
static double tickFrequency = 10000000.0 / System.Diagnostics.Stopwatch.Frequency;
static long UtcToPCDiff = CalcUtcDiff();
private static CalcUtcDiff()
{
return DateTime.Utc.ToBinary() - (long)(Stopwatch.GetTimestamp() * tickFrequency);
}
public static GetUtcNow()
{
return DateTime.FromBinary(UtcToPCDiff + (long)(Stopwatch.GetTimestamp() * tickFrequency));
}
这适用于有限的测试。所有事件都按顺序出现,相对时间戳精确到完整的DateTime精度。但后来我读了许多关于QueryPerformanceCounter不可靠的评论。我意识到,如果PC进入休眠状态然后恢复,或CPU改变频率等,我的时间戳将完全不准确。
我考虑过并被解雇的事情:
但我喜欢定义序列,但时间戳必须至少接近UtcNow。
任何人对如何订购活动都有更好的想法?