Windows编程--线程的身份标识
线程运行时,常常想要调用windows函数来改变它们的运行环境。例如,线程可能 想要改变它的优先级或它的进程的的优先级。线程常常要改变它的(或它进程的)环境,所以Windows提供一些函数,使得线程能够容易地引用它的进程内核对象。或者用它的线程内核对象 :
(FangSH:获得当前的线程和进程的函数)
HANDLE GetCurrentProcess();//伪句柄
HANDLE GetCurrentThread();//伪句柄
1、这两个函数都能返回调用线程的进程的伪句柄或线程内核对象的伪句柄。这些函数并不在创建进程的句柄表中创建新句柄。
2、调用这些函数对进程或线程内核对象的使用计数没有任何影响。
3、如果调用CloseHandle,将伪句柄作为参数来传递,那么CloseHandle就会忽略该函数的调用并返回FALSE。
当调用一个需要进程句柄或线程句柄的Windows函数时,可以传递一个伪句柄,使该函数执行它对调用进程或线程的操作。
例如,通过调用下面的GetProcessTimes函数,线程可以查询它的进程的时间使用情况;同样,通过调用GetThreadTimes函数,线程可以查询它自己的线程时间.
少数Windows函数允许用进程或线程在系统范围内独一无二的ID来标识某个进程或线程。
(这两个函数使可以使线程能够查询它自己唯一的ID或它的里程的唯一的ID)
HANDLE GetCurrentProcessId(); //实句柄
HANDLE GetCurrentThreadId(); //实句柄
这两个函数通常不像能够返回伪句柄的函数那样有用,但是有的时候用起来还是很方便的。
有时候我们要的是“实句柄”,而不是“伪句柄”。
实句柄: 是指用来明确标识一个独一无二的线程的句柄。
(更好的理解参考《伪句柄》)
例如:
DWORD WINAPI ParentThread(PVOID pvParam)
{
HANDLE hThreadParent =GetCurrentThread(); //获得是伪句柄
CreateThread(NULL, 0 ,ChildThread, (PVOID)hThreadParent, 0, NULL);
//Function continues...
}
DWORD WINAPI ChildThread(PVOID pvParam)
{
HANDLE hThreadParent =(HANDLE) pvParam;
FILETIME ftCreationTime,ftExitTime, ftKernelTime, ftUserTime;
GetThreadTimes(hThreadParent,&ftCreationTime,
&ftExitTime,&ftKernelTime, &ftUserTime);
// Function continues...
}
这个代码的目的是让父线程给子线程传递一个线程句柄,以标识父线程。但是,存在一个问题。父线程传递了一个伪句柄,而不是一个实句柄。当子线程开始运行时,它将一个伪句柄传递给GetThreadTime函数,使子线程得到它自己的CPU时间,而不是父线程的CPU时间。出现这种情况的原因是线程的伪句柄是当前线程的句柄,也就是说,它是调用函数的线程的句柄。
必须将伪句柄变成实句柄。DuplicateHandle函数能够执行这一转换:
(FangSH注:DuplicateHandle 1、线程和进程都能转换;2、会使特定对象的使用计数递增)
BOOL DuplicateHandle(
HANDLE hSourceProcess,
HANDLE hSource,
HANDLE hTargetProcess,
PHANDLE phTarget,
DWORD fdwAccess,
BOOL bInheritHandle,
DWORD fdwOptions);
通常可以使用这个函数,用与另一个进程相关的内核对象来创建一个与进程相关的新句柄。然而,可以用一种特殊的方法来使用这个函数。正确的代码段修改如下:
DWORD WINAPI ParentThread(PVOID pvParam) {
HANDLE hThreadParent;
DuplicateHandle(
GetCurrentProcess(), // 进程的伪句柄
GetCurrentThread(), // 线程的伪句柄
GetCurrentProcess(), // 进程的实句柄
&hThreadParent, // 线程转换后的实句柄
0, //Ignored due to DUPLICATE_SAME_ACCESS
FALSE, // 新线程不被继承
DUPLICATE_SAME_ACCESS); // Newthread handle has same
// access as pseudo-handle
CreateThread(NULL, 0, ChildThread, (PVOID) hThreadParent, 0, NULL);
// Function continues...
}
DWORD WINAPI ChildThread(PVOID pvParam) {
HANDLE hThreadParent = (HANDLE) pvParam;
FILETIME ftCreationTime, ftExitTime, ftKernelTime, ftUserTime;
GetThreadTimes(hThreadParent, &ftCreationTime,
&ftExitTime, &ftKernelTime, &ftUserTime);
CloseHandle(hThreadParent);
// Function continues...
}
当父线程运行时,它就将标识父线程所用的伪句柄转换成明确标识父线程所用的新的实句柄。同时它将这个实句柄传递给CreateThread。当子线程启动运行时,它的pvParam参数包含了线程的实句柄。对传递该句柄的函数的任何调用都将影响父线程而不是子线程。
由于DuplicateHandle会递增特定对象的使用计数,因此当完成对复制对象句柄的使用时,应该将目标句柄传递给CloseHandle,从而递减对象的使用计数,这一点很重要。上面的代码段已经显示出这一点。在调用GetThreadTimes之后,紧接着子线程调用CloseHandle,以便递减父线程对象的使用计数。在这个代码段中,我假设子线程不使用该句柄来调用任何其他函数。如果其他函数被调用,以便传递父线程的句柄,那么在子线程不再需要该句柄之前,不应该调用CloseH andle。
还要指出,DuplicateHandle可以用来将进程的伪句柄转换成进程的实句柄,如下面的代码所示:
HANDLE hProcess;
DuplicateHandle(
GetCurrentProcess(), //Handle of process that the process
// pseudo-handle is relative to
GetCurrentProcess(), //Process's pseudo-handle
GetCurrentProcess(), //Handle of process that the new, real,
// process handle is relative to
&hProcess, // Will receive the new, real
// handle identifyingthe process
0, // Ignored because of DUPLICATE_SAME_ACCESS
FALSE, // New thread handle is not inheritable
DUPLICATE_SAME_ACCESS); // New process handle has same
//access as pseudo-handle
FangSH 2010年12月28日星期二