Windows API笔记(一)内核对象
Windows API笔记(二)进程和进程间通信、进程边界
Windows API笔记(三)线程和线程同步、线程局部存储
Windows API笔记(三)线程同步
Windows API笔记(四)win32内存结构
Windows API笔记(五)虚拟内存
Windows API笔记(六)内存映射文件
Windows API笔记(七)堆
Windows API笔记(八)文件系统
Windows API笔记(九)窗口消息
Windows API笔记(十)动态链接库
Windows API笔记(十一)设备I/O
何时创建?何时不需要创建?
HANDLE CreateThread(
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, // 安全描述符,与其他内核对象相同意义
_In_ SIZE_T dwStackSize, // 栈内存空间大小,0 时使用默认值(1MB)
_In_ LPTHREAD_START_ROUTINE lpStartAddress, // 线程函数地址
_In_opt_ __drv_aliasesMem LPVOID lpParameter, // 线程函数参数
_In_ DWORD dwCreationFlags, // 控制线程的创建;0 立刻开始执行;CREATE_SUSPENDED 创建后挂起,并不立即执行
_Out_opt_ LPDWORD lpThreadId // 返回线程id
);
#include
#include
DWORD WINAPI MyThreadFunc(LPVOID lpParm)
{
Sleep(3 * 1000);
LPDWORD mainThreadId = (LPDWORD)lpParm;
DWORD tid = GetCurrentThreadId();
printf("Main Thread Id : %ld , Current Thread Id : %ld\n", *mainThreadId, tid);
return 0;
}
void CreateThreadFunc()
{
DWORD mainThreadId = GetCurrentThreadId();
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.bInheritHandle = false; // 不可被继承
sa.lpSecurityDescriptor = NULL; //安全描述符
DWORD tid;
HANDLE thnd = CreateThread(&sa, 0, MyThreadFunc, &mainThreadId, 0, &tid);
printf("create thread id : %d \n", tid);
CloseHandle(thnd);
// 注意线程同步问题,如果当前函数先退出,局部mainThreadId变量将会释放,传递到线程中的mainThreadId地址将会失效
// Sleep(10*1000);
}
int main()
{
CreateThreadFunc();
Sleep(10 * 1000);
system("pause");
}
Context存储了CPU寄存器的状态。
// 使用此函数前需调用SuspendThread挂起线程,否则将不能获取
BOOL GetThreadContext(
_In_ HANDLE hThread,
_Inout_ LPCONTEXT lpContext
);
//
// Context Frame
//
// This frame has a several purposes: 1) it is used as an argument to
// NtContinue, 2) it is used to constuct a call frame for APC delivery,
// and 3) it is used in the user level thread creation routines.
//
//
// The flags field within this record controls the contents of a CONTEXT
// record.
//
// If the context record is used as an input parameter, then for each
// portion of the context record controlled by a flag whose value is
// set, it is assumed that that portion of the context record contains
// valid context. If the context record is being used to modify a threads
// context, then only that portion of the threads context is modified.
//
// If the context record is used as an output parameter to capture the
// context of a thread, then only those portions of the thread's context
// corresponding to set flags will be returned.
//
// CONTEXT_CONTROL specifies SegSs, Rsp, SegCs, Rip, and EFlags.
//
// CONTEXT_INTEGER specifies Rax, Rcx, Rdx, Rbx, Rbp, Rsi, Rdi, and R8-R15.
//
// CONTEXT_SEGMENTS specifies SegDs, SegEs, SegFs, and SegGs.
//
// CONTEXT_FLOATING_POINT specifies Xmm0-Xmm15.
//
// CONTEXT_DEBUG_REGISTERS specifies Dr0-Dr3 and Dr6-Dr7.
//
typedef struct DECLSPEC_ALIGN(16) _CONTEXT {
//
// Register parameter home addresses.
//
// N.B. These fields are for convience - they could be used to extend the
// context record in the future.
//
DWORD64 P1Home;
DWORD64 P2Home;
DWORD64 P3Home;
DWORD64 P4Home;
DWORD64 P5Home;
DWORD64 P6Home;
//
// Control flags.
//
DWORD ContextFlags;
DWORD MxCsr;
//
// Segment Registers and processor flags.
//
WORD SegCs;
WORD SegDs;
WORD SegEs;
WORD SegFs;
WORD SegGs;
WORD SegSs;
DWORD EFlags;
//
// Debug registers
//
DWORD64 Dr0;
DWORD64 Dr1;
DWORD64 Dr2;
DWORD64 Dr3;
DWORD64 Dr6;
DWORD64 Dr7;
//
// Integer registers.
//
DWORD64 Rax;
DWORD64 Rcx;
DWORD64 Rdx;
DWORD64 Rbx;
DWORD64 Rsp;
DWORD64 Rbp;
DWORD64 Rsi;
DWORD64 Rdi;
DWORD64 R8;
DWORD64 R9;
DWORD64 R10;
DWORD64 R11;
DWORD64 R12;
DWORD64 R13;
DWORD64 R14;
DWORD64 R15;
//
// Program counter.
//
DWORD64 Rip;
//
// Floating point state.
//
union {
XMM_SAVE_AREA32 FltSave;
struct {
M128A Header[2];
M128A Legacy[8];
M128A Xmm0;
M128A Xmm1;
M128A Xmm2;
M128A Xmm3;
M128A Xmm4;
M128A Xmm5;
M128A Xmm6;
M128A Xmm7;
M128A Xmm8;
M128A Xmm9;
M128A Xmm10;
M128A Xmm11;
M128A Xmm12;
M128A Xmm13;
M128A Xmm14;
M128A Xmm15;
} DUMMYSTRUCTNAME;
} DUMMYUNIONNAME;
//
// Vector registers.
//
M128A VectorRegister[26];
DWORD64 VectorControl;
//
// Special debug control registers.
//
DWORD64 DebugControl;
DWORD64 LastBranchToRip;
DWORD64 LastBranchFromRip;
DWORD64 LastExceptionToRip;
DWORD64 LastExceptionFromRip;
} CONTEXT, *PCONTEXT;
BOOL GetThreadTimes(
_In_ HANDLE hThread, // 线程句柄
_Out_ LPFILETIME lpCreationTime, // 线程的创建时间
_Out_ LPFILETIME lpExitTime, // 线程的退出时间,还在运行时无意义
_Out_ LPFILETIME lpKernelTime, // 线程用于执行操作系统代码的时间
_Out_ LPFILETIME lpUserTime // 线程用于执行应用程序代码的时间
);
可以用此函数判断一个复杂算法所必须的时间。
相应的还有进程的执行时间:
BOOL GetProcessTimes(
_In_ HANDLE hProcess, // 进程句柄
_Out_ LPFILETIME lpCreationTime, // 进程创建时间
_Out_ LPFILETIME lpExitTime, // 进程的退出时间
_Out_ LPFILETIME lpKernelTime, // 进程运行系统代码的时间
_Out_ LPFILETIME lpUserTime // 进程运行用户代码的时间
);
有三种方法来终止:
/*
获取当前进程的伪句柄,不创建新句柄,也不增加使用计数
返回值传入CloseHandle不做任何操作就返回了
但是可以把伪句柄传递给需要进程句柄的函数调用
*/
HANDLE GetCurrentProcess(VOID)
/*获取当前线程的伪句柄*/
HANDLE GetCurrentThread(VOID)
/*使用伪句柄转换成一个真句柄*/
HANDLE hProcess;
DuplicateHandle(
GetCurrentProcess(),
GetCurrentProcess(),
GetCurrentProcess(),
&hProcess,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
类 | CreateProcess标志 | 级别 |
---|---|---|
空闲 | IDLE_PRIORITY_CLASS | 4 |
普通(Normal) | NORMAL_PRIORITY_CLASS | 8 |
高(High) | HIGH_PRIORITY_CLASS | 13 |
实时(Realtime) | REALTIME_PRIORITY_CLASS | 24 |
将优先级标志在创建进程CreateProcess时传递给fdwCreate标志。默认普通优先级。
如果不想程序干扰其他程序的运行,可将程序优先级设为空闲,只有在其他程序空闲时才可被执行。屏幕保护程序是一个很好的例子,当用户空闲了某一特定时间段后,屏幕保护程序就激活自己。
/*改变进程优先级*/
BOOL SetPriorityClass(
_In_ HANDLE hProcess, // 线程句柄
_In_ DWORD dwPriorityClass // 优先级
);
进程转前台时,将改变时间片大小。
当线程创建时,优先级是所在进程的优先级。在进程内可以通过调用SetThreadPriority函数改变一个线程的相对优先级:
// 设置线程相对优先级
BOOL SetThreadPriority(
_In_ HANDLE hThread, //线程句柄
_In_ int nPriority //相对优先级
);
// 查询线程的相对优先级
int GetThreadPriroty(HANDLE hThread);
标识符 | 含义 |
---|---|
THREAD_PRIORITY_LOWEST | 所属进程优先级-2 |
THREAD_PRIORITY_BELOW_NORMAL | 所属进程优先级-1 |
THREAD_PRIORITY_NORMAL | 所属进程优先级(默认) |
THREAD_PRIORITY_ABOVE_NORMAL | 所属进程优先级+1 |
THREAD_PRIORITY_HIGHEST | 所属进程优先级+2 |
THREAD_PRIORITY_IDLE | 设线程优先级为1,进程优先级为实时的话设为16 (进程优先级 - 15) |
THREAD_PRIORITY_TIME_CRITICAL | 设线程优先级为15,进程优先级为实时的话设为31 |
线程相对优先级 | IDLE_PRIORITY_CLASS(空闲) | NORMAL_PRIORITY_CLASS(普通) | HIGH_PRIORITY_CLASS(高) | REALTIME_PRIORITY_CLASS(实时) |
---|---|---|---|---|
THREAD_PRIORITY_IDLE(空闲) | 1 | 1 | 1 | 16 |
THREAD_PRIORITY_LOWEST(最低) | 2 | 6 | 11 | 22 |
THREAD_PRIORITY_BELOW_NORMAL(低于普通) | 3 | 7 | 12 | 23 |
THREAD_PRIORITY_NORMAL(普通) | 4 | 8 | 13 | 24 |
THREAD_PRIORITY_ABOVE_NORMAL(高于普通) | 5 | 9 | 14 | 25 |
THREAD_PRIORITY_HIGHEST(最高) | 6 | 10 | 15 | 26 |
THREAD_PRIORITY_TIME_CRITICAL(时间关键) | 15 | 15 | 15 | 31 |
挂起计数
查看进程内的线程
Microsoft在VC++中附带了6中C运行时库:
库名 | 描述 |
---|---|
LIBC.LIB | 静态链接库的发行版本,用于单个线程的应用 |
LIBCD.LIB | 静态链接库的调试版本,用于单个线程的应用 |
LIBCMT.LIB | 静态链接库的发行版本,用于多线程的应用 |
LIBCMTD.LIB | 静态链接库的调试版本,用于多线程的应用 |
MSVCRT.LIB | 动态链接库MSVCRT.DLL的发行版本的引入库,用于单线程和多线程的应用 |
MSVCRTD.LIB | 动态链接库MSVCRTD.DLL的调试版本的引入库,用于多线程和单线程的应用 |
创建线程时,应避免使用 _beginthread和_endthread,而应该使用_beginthreadex和_endthreadex。
_beginthread和_endthread设计过时,没有线程优先级的设置。