"Why are there no odd Windows process Ids?"
The same code that allocates kernel handles is also used to
allocate process and thread IDs. Since kernel handles are a multiple
of four, so too are process and thread IDs.
Why are process and thread IDs multiples of four?
On Windows NT-based operating systems, process and thread IDs happen
always to be a multiple of four. Is this just a coincidence?
Yes, it's just a coincidence, and you shouldn't rely on it since it is
not part of the programming contract. For example, Windows 95 process
and thread IDs were not always multiples of four. (By comparison, the
reason that kernel handles are always a multiple of four is part of
the specification and will be guaranteed for the foreseeable future.)
Process and thread IDs are multiples of four as a side-effect of code
re-use. The same code that allocates kernel handles is also used to
allocate process and thread IDs. Since kernel handles are a multiple
of four, so too are process and thread IDs. This is an implementation
detail, so don't write code that relies on it. I'm just telling you to
satisfy your curiosity.
Source Why are process and thread IDs multiples of four?
Why are kernel HANDLEs always a multiple of four?
Not very well known is that the bottom two bits of kernel HANDLEs are
always zero; in other words, their numeric value is always a multiple
of 4. Note that this applies only to kernel HANDLEs; it does not apply
to pseudo-handles or to any other type of handle (USER handles, GDI
handles, multimedia handles...) Kernel handles are things you can pass
to the CloseHandle function.
The availability of the bottom two bits is buried in the ntdef.h
header file:
//
// 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
That at least the bottom bit of kernel HANDLEs is always zero is
implied by the GetQueuedCompletionStatus function, which indicates
that you can set the bottom bit of the event handle to suppress
completion port notification. In order for this to work, the bottom
bit must normally be zero.
This information is not useful for most application writers, which
should continue to treat HANDLEs as opaque values. The people who
would be interested in tag bits are those who are implementing
low-level class libraries or are wrapping kernel objects inside a
larger framework.
Source Why are kernel HANDLEs always a multiple of four?
Further reading