Starting and Stopping Threads

When you add threads to a process, you need to consider the costs to your process. Create only the number of threads that help your application respond and perform better. You can save time by multitasking, but remember that additional CPU time is needed to keep track of multiple threads. When you are deciding how many threads to create, you also need to consider what data can be process-specific, and what data is thread-specific. Sharing Resources discusses synchronizing access to variables and data.

One single call to the CreateThread function creates a thread, specifies security attributes and memory stack size, and names the routine for the thread to run. Windows allocates memory for the thread stack in the virtual address space of the application that contains the thread. Once a thread has finished processing, the CloseHandle routine frees the resources used by the thread.

For more information:

Starting Threads

The function CreateThread creates a new thread. Its return value is an INTEGER(4) thread handle, used in communicating to the thread and when closing it. The syntax for this function is:

CreateThread (security, stack, thread_func, argument, flags, thread_id)

All arguments are INTEGER(4) variables except for thread_func, which names the routine for CreateThread to run. Minimum requirements for thread_func are discussed in Thread Routine Format. The arguments are as follows:

security This argument uses the SECURITY_ATTRIBUTES type, defined in DFMT.F90. If security is zero, the thread has the default security attributes of the parent process. For more information about setting security attributes for processes and threads, see the Platform SDK online reference.
stack Defines the stack size of the new thread. All of an application's default stack space is allocated to the first thread of execution. As a result, you must specify how much memory to allocate for a separate stack for each additional thread your program needs. The CreateThread call allows you to specify the value for the stack size on each thread you create. A value of zero indicates the stack has the same size as the application's primary thread. The size of the stack is increased dynamically, if necessary, up to a limit of 1 MB.
thread_func The starting address for the thread function.
argument An optional argument for thread_func. Your program defines this parameter and how it is used.
flags This argument lets you create a thread that will not begin processing until you signal it. The flags argument can take either of two values: 0 or CREATE_SUSPENDED. If you specify 0, the thread is created and runs immediately after creation. If you specify CREATE_SUSPENDED, the thread is created, but does not run until you call the ResumeThread function.
thread_id This argument is returned by CreateThread. It is a unique identifier for the thread, which you can use when calling other multithread routines. While the thread is running, no other thread has the same identifier. However, the operating system may use the identifier again for other threads once this one has completed.

A thread can be referred to by its handle as well as its unique thread identifier. Synchronization functions such as WaitForSingleObject and WaitForMultipleObjects take the thread handle as an argument.

Stopping Threads

The ExitThread routine allows a thread to stop its own execution. The syntax is:

CALL EXITTHREAD ( [ Termination Status ] )

Termination status may be queried by another thread. A termination status of 0 indicates normal termination. You can assign other termination status values and their meaning in your program.

When the called thread is no longer needed, the calling thread needs to close the handle for the thread. Use the CloseHandle routine to free memory used by the thread. A thread object is not deleted until the last thread handle is closed.

It is possible for more than one handle to be open to a thread: for example, if a program creates two threads, one of which waits for information from the other. In this case, two handles are open to the first thread: one from the thread requesting information, the other from the thread that created it. All handles are closed implicitly when the enclosing process terminates.

The TerminateThread routine allows one thread to terminate another, if the security attributes are set appropriately for both threads. DLLs attached to the thread are not notified that the thread is terminating, and its initial stack is not deallocated. Use Terminate Thread for emergencies only.

Other Thread Support Functions

Scheduling thread priorities is supported through the functions GetThreadPriority and SetThreadPriority. Use the priority class of a thread to differentiate between applications that are time critical and those that have normal or below normal scheduling requirements. If you need to manipulate priorities, be very careful not to give a thread too high a priority, or it can consume all of the available CPU time. A thread with a base priority level above 11 interferes with the normal operation of the operating system. Using REALTIME_PRIORITY_CLASS may cause disk caches to not flush, hang the mouse, and so on.

When communicating with other threads, a thread uses a pseudohandle to refer to itself. A pseudohandle is a special constant that is interpreted as the current thread handle. Pseudohandles are only valid for the calling thread; they cannot be inherited by other threads. The GetCurrentThread function returns a pseudohandle for the current thread. The calling thread can use this handle to specify itself whenever a thread handle is required. Pseudohandles are not inherited.

To get the thread's identifier, use the GetCurrentThreadId function. The identifier uniquely identifies the thread in the system until it terminates. You can use the identifier to specify the thread itself whenever an identifier is required.

Use GetExitCodeThread to find out if a thread is still active, or if it is not, to find its exit status. Call GetLastError for more detailed information on the exit status. If one routine depends on a task being performed by a different thread, use the wait functions described in Synchronizing Threads instead of GetExitCodeThread.