A process contains its own independent virtual address space with both code and data, protected from other processes. Each process, in turn, contains one or more independently executing threads. A thread running within a process can execute application code, create new threads, create new independent processes, and manage communication and synchronization among the threads.

By creating and managing processes, applications can have multiple, concurrent tasks processing files, performing computations, or communicating with other networked systems. It is even possible to improve application performance by exploiting multiple CPU processors.

This chapter explains the basics of process management and also introduces the basic synchronization operations and wait functions that will be important throughout the rest of the book.

Windows Processes and Threads

Every process contains one or more threads, and the Windows thread is the basic executable unit; see the next chapter for a threads introduction. Threads are scheduled on the basis of the usual factors: availability of resources such as CPUs and physical memory, priority, fairness, and so on. Windows has long supported multiprocessor systems, so threads can be allocated to separate processors within a computer.

From the programmer’s perspective, each Windows process includes resources such as the following components:

  • One or more threads.
  • A virtual address space that is distinct from other processes’ address spaces. Note that shared memory-mapped files share physical memory, but the sharing processes will probably use different -virtual addresses to access the mapped file.
  • One or more code segments, including code in DLLs.
  • One or more data segments containing global variables.
  • Environment strings with environment variable information, such as the -current search path.
  • The process heap.
  • Resources such as open handles and other heaps.

Each thread in a process shares code, global variables, environment strings, and resources. Each thread is independently scheduled, and a thread has the following elements:

  • A stack for procedure calls, interrupts, exception handlers, and automatic storage.
  • Thread Local Storage (TLS)-An arraylike collection of pointers giving each thread the ability to allocate storage to create its own unique data environment.
  • An argument on the stack, from the creating thread, which is usually unique for each thread.
  • A context structure, maintained by the kernel, with machine register values.

Figure 6-1 shows a process with several threads. This figure is schematic and does not indicate actual memory addresses, nor is it drawn to scale.

Figure 6-1: A Process and Its Threads

This chapter shows how to work with processes consisting of a single thread. Chapter 7 shows how to use multiple threads.

Note: Figure 6-1 is a high-level overview from the programmer’s perspective. There are numerous technical and implementation details, and interested readers can find out more in Russinovich, Solomon, and Ionescu, Windows Internals: Including Windows Server 2008 and Windows Vista.

NOTE: A UNIX process is comparable to a Windows process.

Threads, in the form of POSIX Pthreads, are now nearly universally available and used in UNIX and Linux. Pthreads provides features similar to Windows threads, although Windows provides a broader collection of functions.

Vendors and others have provided various thread implementations for many years; they are not a new concept. Pthreads is, however, the most widely used standard, and proprietary implementations are long obsolete. There is an open source Pthreads library for Windows.

Process Creation

The fundamental Windows process management function is CreateProcess, which creates a process with a single thread. Specify the name of an executable program file as part of the CreateProcess call.

It is common to speak of parent and child processes, but Windows does not actually maintain these relationships. It is simply convenient to refer to the process that creates a child process as the parent.

CreateProcess has 10 parameters to support its flexibility and power. Initially, it is simplest to use default values. Just as with CreateFile, it is appropriate to explain all the CreateProcess parameters. Related functions are then easier to understand.

Note first that the function does not return a HANDLE; rather, two separate handles, one each for the process and the thread, are returned in a structure specified in the call. CreateProcess creates a new process with a single primary thread (which might create additional threads). The example I programs are always very careful to close both of these handles when they are no longer needed in order to avoid resource leaks; a common defect is to neglect to close the thread handle. Closing a thread handle, for instance, does not terminate the thread; the CloseHandle function only deletes the reference to the thread within the process that called CreateProcess.

BOOL Create Process (
   LPCTSTR lpApplicationName,
   LPTSTR lpCommandLine,
   LPSECURITY_ATTRIBURES IpsaProcess,
   LPSECURITY_ATTRIBUTES lpsaThread,
   BOOL bInheritHandles,
   DWORD dwCreationFlags,
   DPVOID lpEnvironment,
   LPCTSTR lpCurDir,
   LPSTARTUPINFO lpStartupInfo
   LPPROCESS_INFORMATION lpProcInfo
    
Return: TRUE only if the process and thread are successfully created.

Parameters

Some parameters require extensive explanations in the following sections, and many are illustrated in the program examples.

lpApplicationName and lpCommandLine (this is an LPTSTR and not an LPCTSTR) together specify the executable program and the command line arguments, as explained in the next section.

lpsaProcess and lpsaThread point to the process and thread security attribute structures. NULL values imply default security and will be used until Chapter 15, which covers Windows security.

bInheritHandles indicates whether the new process inherits copies of the calling process’s inheritable open handles (files, mappings, and so on). Inherited handles have the same attributes as the originals and are discussed in detail in a later section.

dwCreationFlags combines several flags, including the following.

  • CREATE_SUSPENDED indicates that the primary thread is in a suspended state and will run only when the program calls ResumeThread.
  • DETACHED_PROCESS and CREATE_NEW_CONSOLE are mutually exclusive; don’t set both. The first flag creates a process without a console, and the second flag gives the new process a console of its own. If neither flag is set, the process inherits the parent’s console.
  • CREATE_UNICODE_ENVIRONMENT should be set if UNICODE is defined.
  • CREATE_NEW_PROCESS_GROUP specifies that the new process is the root of a new process group. All processes in a group receive a console control signal (Ctrl-c or Ctrl-break) if they all share the same console. Console control handlers were described in Chapter 4 and illustrated in Program 4-5. These process groups have limited similarities to UNIX process groups and are described later in the “Generating Console Control Events” section.

Several of the flags control the priority of the new process’s threads. The possible values are explained in more detail at the end of Chapter 7. For now, just use the parent’s priority (specify nothing) or NORMAL_PRIORITY_CLASS.

lpEnvironment points to an environment block for the new process. If NULL, the process uses the parent’s environment. The environment block contains name and value strings, such as the search path.

lpCurDir specifies the drive and directory for the new process. If NULL, the parent’s working directory is used.

lpStartupInfo is complex and specifies the main window appearance and standard device handles for the new process. We’ll use two principal techniques to set the start up information. Programs 6-1, 6-2, 6-3, and others show the proper sequence of operations, which can be confusing.

  • Use the parent’s information, which is obtained from GetStartupInfo.
  • First, clear the associated STARTUPINFO structure before calling CreateProcess, and then specify the standard input, output, and error handles by setting the STARTUPINFO standard handler fields (hStdInput, hStdOutput, and -hStdError). For this to be effective, also set another STARTUPINFO member, dwFlags, to STARTF_USESTDHANDLES, and set all the handles that the child process will require. Be certain that the handles are inheritable and that the CreateProcess bInheritHandles flag is set. The “Inheritable Handles” subsection gives more information.

The entire chapter can be found here: http://www.informit.com/articles/article.aspx?p=1564827