线程控制
Posted shiningarmor
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程控制相关的知识,希望对你有一定的参考价值。
1.线程控制
控制线程状态的API函数:
//挂起线程: ::SuspendThread(hThread); //恢复线程: ::ResumeThread(hThread); //终止线程: //方式一: ::ExitThread(DWORD dwExitCode); //参数中没有线程句柄,在线程函数中使用; //参数dwExitCode为线程退出码,将作为线程处理函数的返回值,用来描述线程的非正常退出 //每一个线程都有自己的堆栈,该函数终止的线程会清理堆栈; //该函数一旦调用,线程将不能再被操作,但该函数并不会释放堆中的内存,因此存在内存溢出的隐患; //方式二:线程函数返回 //线程函数执行完后会结束线程,因为是正常结束,可以自己写代码来释放堆中申请的内存; //方式三: ::TerminateThread(hThread,2); //第二个参数为线程退出码 ::WaitForSingleObject(hThread,INFINITE); //TerminateThread并不会清理堆栈,这样的好处是其它地方用堆栈中的变量时不会出问题; //判断线程是否结束 BOOL GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode ); //STILL_ACTIVE //正在运行 //参数: //hThread: 要结束的线程句柄 //dwExitCode: 指定线程的退出代码。可以通过GetExitCodeThread来查看一个线程的退出代码
ExitThread和TerminateThread的区别:
都是用来结束线程的,ExitThread是同步的,也就是ExitThread执行完后程序才能继续往下执行;
TerminateThread是异步调用;也就是单独起了一个线程来让目标线程结束;
TerminateThread调用后不能保证立即结束线程,在后面写线程结束后要执行的代码可能有问题;
解决办法是用 WaitForSingleObject,该函数会阻塞线程直到TerminateThread的目标线程真正结束;
线程挂起后恢复时并不会立即运行;
因为windows并不是实时的操作系统,只有在调度程序给可调度状态的线程分配cpu时间时才会运行;
因此windows中无法实现在某个确定的时间点运行一个线程;
2.线程contex结构
每个线程在执行的时候,都会独自占用一个CPU,
当系统中的线程数量 > CPU的数量时,就会存在多个线程共用一个CPU的情况。
但CPU每次只能运行一个线程,Windows每隔20毫秒会进行线程的切换,
那比如线程A执行到地址:0x2345678 eax:1 ecx:2 edx:3 ebx:4...还有eflag标志寄存器中的值等等。。。
此时,线程执行时间到了,被切换到了线程B。。。。
当线程B的时间片也到了,再切换回线程A时,系统是如何知道该从哪个地址开始执行呢?被切换前用到的各种寄存器的值该如何恢复呢?
context结构:该结构包含了特定cpu的寄存器数据
typedef struct _CONTEXT { // // The flags values within this flag control 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 will be modified. // // If the context record is used as an IN OUT parameter to capture // the context of a thread, then only those portions of the thread‘s // context corresponding to set flags will be returned. // // The context record is never used as an OUT only parameter. // DWORD ContextFlags; // // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT // included in CONTEXT_FULL. // DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; // // This section is specified/returned if the // ContextFlags word contians the flag CONTEXT_FLOATING_POINT. // FLOATING_SAVE_AREA FloatSave; // // This section is specified/returned if the // ContextFlags word contians the flag CONTEXT_SEGMENTS. // DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; // // This section is specified/returned if the // ContextFlags word contians the flag CONTEXT_INTEGER. // DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; // // This section is specified/returned if the // ContextFlags word contians the flag CONTEXT_CONTROL. // DWORD Ebp; DWORD Eip; DWORD SegCs; // MUST BE SANITIZED DWORD EFlags; // MUST BE SANITIZED DWORD Esp; DWORD SegSs; // // This section is specified/returned if the ContextFlags word // contains the flag CONTEXT_EXTENDED_REGISTERS. // The format and contexts are processor specific // BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; } CONTEXT; 进程就是程序的4GB空间,线程就是EIP; 当一个线程切换时,为了再次执行时能接着执行,会将寄存器的信息保存context结构中; 如何获取context结构中的值: 例如:获取context中的eip //挂起线程;不挂起获取的值不准确 SuspendThread(线程句柄); CONTEXT context; //设置要获取的类型 context.ContextFlags = CONTEXT_CONTROL; //获取 BOOL ok = ::GetThreadContext(hThread,&context); //设置 context.Eip = 0x401000; SetThreadContext(hThread,&context);
以上是关于线程控制的主要内容,如果未能解决你的问题,请参考以下文章