为什么没有奇怪的Windows进程ID?


160

在Windows中,有许多方法可以检查进程ID。

例如,使用PowerShell命令:

ps | select Id, ProcessName  | Sort Id | ft -AutoSize

我们看到以下输出:

  Id ProcessName         
  -- -----------         
   0 Idle                
   4 System              
 264 svchost             
 388 smss                
 476 csrss               
 536 wininit             
 580 winlogon                      
 620 services            
 628 lsass                          
 728 svchost             
 828 dwm                                     
1060 chrome              
1080 rundll32            
1148 vmms                                        
1620 spoolsv                                                
2912 taskhostex          
3020 explorer       
...     

所有进程ID均为偶数,此外,它们均为4的倍数

在基于Windows NT的任何版本的Windows上都没有奇数的进程ID。

这是什么原因呢?


6
可能很有趣:有关linux的一些详细信息-justskins.com/forums/why-are-process-ids-204416.html
Dave

13
确实没有。真奇怪
AndreKR 2015年

Answers:


168

“为什么没有奇怪的Windows进程ID?”

分配内核句柄的相同代码也用于分配进程和线程ID。由于内核句柄是四个的倍数,因此进程和线程ID也是如此。


为什么进程和线程ID为4的倍数?

在基于Windows NT的操作系统上,进程和线程ID总是总是四个的倍数。这只是巧合吗?

是的,这只是一个巧合,您不应该依赖它,因为它不是编程合同的一部分。例如对于Windows 95进程和线程ID并不总是四个的倍数。(通过比较,内核句柄始终是四个的倍数的原因是该规范的一部分,并且在可预见的将来将得到保证。)

进程和线程ID是代码重用的副作用,是四的倍数。分配内核句柄的相同代码也用于分配进程和线程ID。由于内核句柄是4的倍数,因此进程和线程ID也是如此。这是一个实现细节,因此不要编写依赖它的代码。我只是告诉你要满足你的好奇心。

来源为什么进程和线程ID是四的倍数?


为什么内核句柄总是四个的倍数?

内核HANDLE的后两位始终为零,这一点不是很清楚。换句话说,它们的数值始终是4的倍数。注意,这仅适用于内核HANDLE。它不适用于伪句柄或任何其他类型的句柄(用户句柄,GDI句柄,多媒体句柄...)。内核句柄是可以传递给CloseHandle函数的东西。

后两位的可用性隐藏在ntdef.h头文件中:

//
// Low order two bits of a handle are ignored by the system and available
// for use by application code as tag bits.  The remaining bits are opaque
// and used to store a serial number and table index.
//

#define OBJ_HANDLE_TAGBITS  0x00000003L

GetQueuedCompletionStatus函数暗示至少内核HANDLEs的最低位始终为零,这表明您可以设置事件句柄的最低位来禁止完成端口通知。为了使其正常工作,最低位通常必须为零。

此信息对大多数应用程序编写者没有用,应继续将HANDLE作为不透明值来对待。对标记位感兴趣的人是那些实现低级类库或将内核对象包装在更大框架中的人。

来源为什么内核句柄总是4的倍数?


进一步阅读



3
一句名言说“您不应该依赖它,因为它不是编程合同的一部分,”然后下一个声明ntdef.h说这些位“可被应用程序代码用作标记位”。 公共头文件中的文档与您可能获得的“编程合同”差不多,因此第一个声明不正确。
BlueRaja-Danny Pflughoeft 2015年

2
@BlueRaja,“不太了解内核HANDLE的底部两位始终为零;换句话说,它们的数值始终为4的倍数。 ” ntdef.h中的代码也适用于其他类型的句柄(USER句柄,GDI句柄,多媒体句柄...)
DavidPostill

37
@BlueRaja:内核句柄是四个的倍数,这是契约性的,因此您可以依靠它;进程ID(这是作为进程处理相同),而是发生是多四个,但是这只是一个实现细节,所以你不应该依赖于它。
Matteo Italia 2015年

6
@BlueRaja我想雷蒙德会告诉您,撰写文档的人都是通过有色内核的眼镜来查看世界的,因此仅指内核句柄,而不是其他类型的句柄。
CodesInChaos

1
@Mehrdad:嗯,USER和GDI句柄通常不称为“内核”句柄(尽管它们是由以所谓的内核模式运行的组件生成的)。
Matteo Italia
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.