我正试图测量在线程中花费的时间以用于进度报告目的,但我从 GetThreadTimes 系统调用中得到了非常奇怪的结果。给定以下程序(在 VS 2013 中编译,针对 .NET 4.5):
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
namespace ThreadTimingTest
{
class Program
{
static Stopwatch _wallClockTimer;
static System.Timers.Timer _timer = new System.Timers.Timer();
private static Thread _thread;
private static IntPtr _threadHandle;
static void Main(string[] args)
{
_timer = new System.Timers.Timer();
_timer.Elapsed += (s, e) =>
{
System.Runtime.InteropServices.ComTypes.FILETIME start, end, rawKernelTime, rawUserTime;
GetThreadTimes(_threadHandle, out start, out end, out rawKernelTime, out rawUserTime);
//ref: http://stackoverflow.com/a/6083846
ulong uLow = (ulong)rawKernelTime.dwLowDateTime;
ulong uHigh = (uint)rawKernelTime.dwHighDateTime;
uHigh = uHigh << 32;
long kernelTime = (long)(uHigh | uLow);
uLow = (ulong)rawUserTime.dwLowDateTime;
uHigh = (uint)rawUserTime.dwHighDateTime;
uHigh = uHigh << 32;
long userTime = (long)(uHigh | uLow);
Debug.WriteLine("Kernel time: " + kernelTime);
Debug.WriteLine("User time: " + userTime);
Debug.WriteLine("Combined raw execution time: " + (kernelTime + userTime));
long elapsedMilliseconds = (kernelTime + userTime) / 10000; //convert to milliseconds: raw timing unit is 100 nanoseconds
Debug.WriteLine("Elapsed thread time: " + elapsedMilliseconds + " milliseconds");
Debug.WriteLine("Wall Clock Time: " + _wallClockTimer.ElapsedMilliseconds + " milliseconds");
};
_timer.Interval = 1000;
_wallClockTimer = new Stopwatch();
Debug.WriteLine("Starting...");
RunTest();
Debug.WriteLine("Ended.");
}
public static void RunTest()
{
_thread =
new Thread
(
() =>
{
_threadHandle = GetCurrentThread();
Stopwatch sw = Stopwatch.StartNew();
while (sw.ElapsedMilliseconds < 3000)
{
int i = 1 + 2;
} //do busy-work for 3 seconds
sw.Stop();
}
);
_timer.Start();
_thread.Start();a
_wallClockTimer.Start();
_thread.Join();
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetThreadTimes(IntPtr hThread,
out System.Runtime.InteropServices.ComTypes.FILETIME lpCreationTime, out System.Runtime.InteropServices.ComTypes.FILETIME lpExitTime,
out System.Runtime.InteropServices.ComTypes.FILETIME lpKernelTime, out System.Runtime.InteropServices.ComTypes.FILETIME lpUserTime);
[DllImport("kernel32.dll")]
private static extern IntPtr GetCurrentThread();
}
}
我得到以下输出:
Starting...
Kernel time: 0
User time: 0
Combined raw execution time: 0
Elapsed thread time: 0 milliseconds
Wall Clock Time: 1036 milliseconds
Kernel time: 0
User time: 0
Combined raw execution time: 0
Elapsed thread time: 0 milliseconds
Wall Clock Time: 2036 milliseconds
The thread '<No Name>' (0x191c) has exited with code 0 (0x0).
Ended.
我希望 GetThreadTimes
报告线程时间不是零:为什么报告零?
最佳答案
根据 Hans 提供的链接对您的代码进行几个简单的修改后,将显示有效时间。
添加一些互操作声明:
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool DuplicateHandle(IntPtr hSourceProcessHandle,
IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle,
uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions);
[Flags]
public enum DuplicateOptions : uint
{
DUPLICATE_CLOSE_SOURCE = (0x00000001), // Closes the source handle. This occurs regardless of any error status returned.
DUPLICATE_SAME_ACCESS = (0x00000002), // Ignores the dwDesiredAccess parameter. The duplicate handle has the same access as the source handle.
}
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentProcess();
然后修改句柄的分配方式:
//_threadHandle = GetCurrentThread(); <-- previous assignment
IntPtr processHandle = GetCurrentProcess();
bool result = DuplicateHandle(processHandle, GetCurrentThread(), processHandle, out _threadHandle, 0, false, (uint) DuplicateOptions.DUPLICATE_SAME_ACCESS);
产生以下结果:
Starting...
Kernel time: 0
User time: 10000000
Combined raw execution time: 10000000
Elapsed thread time: 1000 milliseconds
Wall Clock Time: 1006 milliseconds
Kernel time: 0
User time: 20000000
Combined raw execution time: 20000000
Elapsed thread time: 2000 milliseconds
Wall Clock Time: 2004 milliseconds
Kernel time: 0
User time: 30000000
Combined raw execution time: 30000000
Ended.
Elapsed thread time: 3000 milliseconds
Wall Clock Time: 3045 milliseconds
编辑:
最近,人们付出了大量努力来处理为给定系统创建的过多线程。假设您有一个四核处理器,并且有 20 多个线程都想运行。线程在启动、内核管理、内存(它们有自己的堆栈)等方面具有相当大的成本。与减少线程数相比,系统实际上可能更慢(处理上下文和调度)。所以在 .NET 中,像 TPL 这样的库被创建(允许开发人员管理任务,而不是线程)。这允许 CLR 为目标系统平衡适当的线程数。但是在您的情况下(您显式创建托管线程),与 native 线程几乎总是一对一的关系。
希望这对您有所帮助。
关于c# - 为什么 GetThreadTimes 返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26472936/