Windows Programming/Multitasking

Processes and Threads
Current versions of Windows are multitasking operating systems. In this chapter, we will discuss some of the tools and API functions that are involved in multitasking, threading, and synchronization for use in Windows.

First, let's explain a little bit of terminology. A process is a single program, with a single entry point, and a single exit point. A thread is a part of a process. A process has at least 1 thread; but can have more than 1 thread. When created, processes and threads run automatically and are alloted time slices of execution time by the scheduler in a round-robin fashion. The operating system may activate and deactivate any thread or process at any time. For this reason, we will need to control access to program resources such as global memory and output devices.

If multiple processes are working together, the resulting group is known as a job. Jobs can also be managed by Windows.

Managing Processes

 * CreateProcess, etc

Threads
A few functions are used when dealing with threads, like ,  ,  , and.

If the volatility of threads is disconcerting, Windows also provides an execution object known as a fiber that only runs when activated by the parent thread.

CreateThread
The  function accepts a few parameters:
 * a pointer to the function to be executed within the thread.
 * a pointer to a variable to be passed to the thread's function.

The CreateThread function creates a new thread for a process. The creating thread must specify the starting address of the code that the new thread is to execute. Typically, the starting address is the name of a function defined in the program code. This function takes a single parameter and returns a DWORD value. A process can have multiple threads simultaneously executing the same function.

The following example demonstrates how to create a new thread that executes the locally defined function, ThreadFunc.

For simplicity, this example passes a pointer to a DWORD value as an argument to the thread function. This could be a pointer to any type of data or structure, or it could be omitted altogether by passing a NULL pointer and deleting the references to the parameter in ThreadFunc. It is risky to pass the address of a local variable if the creating thread exits before the new thread, because the pointer becomes invalid. Instead, either pass a pointer to dynamically allocated memory or make the creating thread wait for the new thread to terminate. Data can also be passed from the creating thread to the new thread using global variables. With global variables, it is usually necessary to synchronize access by multiple threads.

Thread Local Storage (TLS)
A single process can (usually) spawn 2000 threads. This is because the default stack size allocated by the linker is 1MB per thread. 1MB x 2000 is around 2GB which is the maximum a user-process can access. Following is a sample code which spawn many threads till a limit is reached:

Debugging
The naming of a thread, a special feature, that only works with a few windows debuggers, is extremely useful for debugging threads, especially when debugging programs with a lot of threads. It consists in generating a special runtime exception (0x406D1388) which allows the program to pass the name for the thread to the debugger.

Next Chapter

 * Interprocess Communication