1. 线程上下文:线程内核对象保存线程上一次执行时的CPU寄存器状态
2. 线程上下文切换
3. windows操作系统为抢占式多线程操作系统,系统可以在任何时刻停止一个线程而另行调度另外一个线程。我们无法保证
线程总在运行,无法保证线程会获得整个处理器而不运行运行其他线程等。
4. 系统只调度可调度的线程,系统中大多数线程都是不可调度的,比如挂起(SUSPENDED)线程或等待线程(等待某些事件发生,
如键盘输入)
5. 枚举线程
CreateToolhelp32Snapshot Thead32First Thread32Next
6. 线程的执行时间
在抢占式操作系统中,我们不可能知道线程什么时候会获得CPU时间,当线程失去CPU时间时,为线程执行的各种任务进行计时很
困难。我们需要的是一个能够返回线程已获得的CPU时间量的函数GetThreadTimes
精度更高的有:QueryPerformanceFrequency和QueryPerformanceCounter
当线程被调度程序暂停时将计算此时TSC值与线程开始执行时间量时的TSC值之差,并在线程执行时间上加上这个差值,不计算中断时间
//typedef struct _FILETIME //{ // DWORD dwLowDateTime; // DWORD dwHighDateTime; //} FILETIME; // 设计概念逻辑左移动和算术左移 INT64 FileTimeToQuadWord(FILETIME* pft) { return (Int64ShllMod32(pft->dwHighDateTime, 32) | pft->dwLowDateTime); } // 函数无法检测 void PerformLongOperation() { FILETIME ftCreateTime; FILETIME ftExitTime; FILETIME ftKernelTimeStart; FILETIME ftKernelTimeEnd; FILETIME ftUserStart; FILETIME ftUserEnd; INT64 qwKernelTimeElapsed, qwUserTimeElapsed, qwTotalTimeElapsed; GetThreadTimes(GetCurrentThread(), &ftCreateTime, &ftExitTime, &ftKernelTimeStart, &ftUserStart); // 进行一系列操作 for ( int i = 0; i < 100; i ++) { int j = i; } GetThreadTimes(GetCurrentThread(), &ftCreateTime, &ftExitTime, &ftKernelTimeEnd, &ftUserEnd); qwKernelTimeElapsed = FileTimeToQuadWord(&ftKernelTimeEnd) - FileTimeToQuadWord(&ftKernelTimeStart); qwUserTimeElapsed = FileTimeToQuadWord(&ftUserEnd) - FileTimeToQuadWord(&ftUserStart); qwTotalTimeElapsed = qwKernelTimeElapsed + qwUserTimeElapsed; }
class CStopwatch { private: // 64位有符号整数可以用INT64 _int64 LARGE_INTEGER表示 LARGE_INTEGER m_nPerfFrequency; LARGE_INTEGER m_nPerFrefStart; public: CStopwatch(){QueryPerformanceFrequency(&m_nPerfFrequency); Start();} void Start(){QueryPerformanceCounter(&m_nPerFrefStart);} INT64 Now() const { LARGE_INTEGER nPerfNow; QueryPerformanceCounter(&nPerfNow); return ((nPerfNow.QuadPart - m_nPerFrefStart.QuadPart) * 1000) / m_nPerfFrequency.QuadPart; } INT64 NowInMicro() const { LARGE_INTEGER nPerfNow; QueryPerformanceCounter(&nPerfNow); return ((nPerfNow.QuadPart - m_nPerFrefStart.QuadPart) * 1000000) / m_nPerfFrequency.QuadPart; } };
7. CONTEXT结构分以下及部分:
CPU控制寄存器:指令指针、栈指针、标志和函数返回地址等
CPU整数寄存器
CPU浮点数寄存器
CPU段寄存器
CPU调试寄存器
CPU扩展寄存器
8. 用户模式下线程同步
1). 原子访问InterLocked系列函数,无论编译器如何生成代码,无论机器上装配了多少个CPU,这些函数都能保证对值的修改是以原子方式进行的。
但是我们必须保证传给这些函数的变量地址是对齐的,否则这些函数可能会失败。
2). 注意原子系列函数返回的是原来的值
3). 关键段CRITICAL_SECTION
CRITICAL_SECTION g_cs;
EnterCriticalSection(&g_cs);
LeaveCriticalSection(&g_cs);
4). SRWLOCK读/写锁
InitializeSRWLOCK(PSRWLOCK SRWLock);
// 独占方式写入者线程
AcquireSRWLockExclusive(PSRWLOCK SRWLock);
ReleaseSRWLockExclusive(PSRWLOCK SRWLock);
// 共享方式读取者线程
AcquireSRWLockShared(PSRWLOCK SRWLock);
ReleaseSRWLockShared(PSRWLOCK SRWLock);
5). 条件变量
BOOL SleepConditionVariableCS(PCONDITIONVARIABLE pConditionVariable, PCRITICAL_SECTION pCriticalSection, DWORD dwMillseconds);
BOOL SleepConditionVariableCS(PCONDITIONVARIABLE pConditionVariable, PSRWLOCK pSRWLock, DWORD dwMillseconds, ULONG Flags);
Flags: 对写入者线程来说应该传入0,表示希望以独占的方式对资源访问
CONDITION_VARIABLE_LOCKMODE_SHARED 表示希望共享对资源的访问
9. 高速缓存行
虽然高速缓存行存在提高性能,但在多处理器的机器上他们能够损伤性能
_declspec (align(32)) struct data { int a; char cBuff[100]; _declspec (align(64)) double d; int c; };
附录:
elapsed 失去过去 elapsedtime
query 询问 QueryPerformanceFrequency
conditionvariable 条件变量
void* _aligned_malloc(size_t size, size_t alignment); 分配一块对齐过的内存
LONG InterlockedExchangeAdd(PLONG volatile plAddend, LONG lIncrement);
LONG InterlockedExchange(PLONG volatile plTarget, LONG lValue);
PVOID InterlockedExchangePointer(PVOID* volatile ppvTarget, PVOID pvValue);
LPCOID HeadAlloc(HEADLE hHeap, DWORD dwFlag, SIZE_T dwBytes);
参数1可以通过GetProcessHeap()获得
参数2 HEAP_GENERATE_EXCEPTIONS 如果分配错误将会抛出异常而不是返回NULL
HEAP_NO_SERIALIZE 不实用连续存储
HEAP_ZERO_MEMORY 将分配的内存全部清零