线程句柄与线程ID:
线程是由Windows内核负责创建与管理的,句柄相当于一个令牌,有了这个令牌就可以使用线程对象.
线程ID是身份证,唯一的,系统进行线程调度的时候要使用的.
HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, // 安全属性 通常为NULL SIZE_T dwStackSize, // 参数用于设定线程可以将多少地址空间用于它自己的堆栈 // 每个线程拥有它自己的堆栈 LPTHREAD_START_ROUTINE lpStartAddress, // 参数用于指明想要新线程执行的线程函数的地址 LPVOID lpParameter, // 线程函数的参数 // 在线程启动执行时将该参数传递给线程函数 // 既可以是数字,也可以是指向包含其他信息的一个数据结构的指针 DWORD dwCreationFlags, // 0 创建完毕立即调度 CREATE_SUSPENDED创建后挂起 LPDWORD lpThreadId // 线程ID ); // 返回值:线程句柄创建线程代码:
//创建一个新的线程
HANDLE hThread = ::CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);//如果不在其他的地方引用它 关闭句柄
::CloseHandle(hThread); DWORD WINAPI ThreadProc(LPVOID lpParameter) { printf("%x\n",(int)lpParameter); return 0; } int main() { int a = 5; printf("%d\n",a); HANDLE hThread = CreateThread(NULL, 0, ThreadProc, (LPVOID)a, 0, NULL); CloseHandle(hThread); return 0; }当我们创建一个线程的时候,如果不进行阻塞,有可能cpu根本没有给线程分配应有的东西,导致线程在main函数执行完了都还没开始启动 所以 要在创建线程以后使用sleep等待
int main() { int a = 5; printf("%d\n",a); HANDLE hThread = CreateThread(NULL, 0, ThreadProc, (LPVOID)a, 0, NULL); Sleep(1000); CloseHandle(hThread); return 0; }在初期的实验中只有这样才能保证线程一定会执行
线程的挂起,恢复和终止
::SuspendThread(hThread); //挂起线程 ::ResumeThread(hThread); //恢复线程 ::ExitThread(DWORD dwExitCode); //线程终止1 ::TerminateThread(hThread,2); //线程终止2 ::WaitForSingleObject(hThread,INFINITE);在自己的进程空间里拉伸pe,挂起主线程,并且将主线程的eip改变到拉伸的pe里
SuspendThread(线程句柄); context.ContextFlags = CONTEXT_CONTROL; BOOL ok = ::GetThreadContext(hThread,&context); context.Eip = 0x401000; SetThreadContext(hThread,&context);获取线程上下文结构,设置eip为拉伸的pe的imagebase