CreateProcess还会为进程和线程分配一个ID号。进程和线程分享同一个号码池。这意味着它们不可能相同。一个对象的ID不可能分配到0,因为windows任务管理器将进程ID 0与系统空闲进程关联。该进程代表未被真实使用的cpu使用率。
dwProcessId和dwThreadId成员就是存储进程和线程的ID。使用GetCurrentProcessId可以获得当前进程的ID。GetCurrentThreadId来获得当前正在运行的线程的ID。另外使用GetProcessId和GetThreadId可以获得指定句柄对应的进程和线程的ID。使用GetProcessIDOfThread可以获得某句柄关联的线程所在进程的ID。
由于ID可能会立即重用。也就是说当我们获得某个进程的ID并保存后,此后在使用时有可能出现它已经被释放了。此时此ID就对应着其他进程了。避免这种情况的唯一方法就是:保证进程或线程对象不被销毁。
进程终止
进程可以通过三种方式终止:
1:主线程从入口函数返回。
2:进程中的一个线程调用ExitProcess。
3:另一个进程中的线程调用TerminateProcess。
在以上介绍的三种方式中仅有第一种,当主线程从入口函数返回才保证主线程的所有资源都会被正确清理。
清理操作包括:
1:调用所有在本进程内使用的任何C++对象的析构函数。
2:释放各个线程线程栈使用的内存。
3:进程的退出代码被设为入口函数的返回值。
4:进程内核对象使用计数递减1。
正常情况下入口点函数会返回到启动函数,启动函数将正确清理进程使用的所有C运行时资源,清理之后启动代码显式调用ExitProcess并将入口函数返回值传给它。这也是为什么只需从入口函数返回却可以终止整个进程的原因。
进程的一个线程调用ExitProcess可以终止本进程。其后的别的代码将不会被执行。
与ExitProcess相类似的还有ExitThread,它会导致一个线程终止。在创建线程时常出现这种情况:子线程还没有怎么执行程序就已经结束了,这有可能是在创建完线程后,主线程没有调用WaitForSingleObject之类的函数,主线程创建完其他线程后就返回到启动函数函数返回整个进程被终止。这一点很容易出错。
调用ExitProcess或是ExitThread会导致进程或线程当场终止运行,再也不会返回到启动函数,清理工作(C++对象的析构)当然没法执行。虽然最终随着进程的结束,该进程内所有线程所使用的资源都会被释放,但是应该避免调用这些函数,它们阻止了C++对象析构函数对善后工作的处理。顺便提下,如果在主线程调用ExitThread,虽然主线程当场终止,但是如果进程内还有其他线程,则进程不会终止。
如以下代码:
#include<windows.h> #include<iostream> DWORD ThreadProc(PVOID) { int i=0; int j=0;
while(i<1000000) { i++; while(j<10000) j++; std::cout<<i<<","<<j<<std::endl; } return 0; } int main(int argc,char**argv) { DWORD id; CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadProc,NULL,0,&id); ExitThread(0); return 0; } |