Most code requires the C library, even if it is just to manipulate strings. Historically, the C library was written to operate in single-threaded processes, so many functions use global storage to store intermediate results. Such libraries are not thread-safe because two separate threads might, for example, be simultaneously accessing the library and modifying the library's global storage. Proper design of threaded code will be discussed again in Chapter 8, which describes Windows synchronization.
The function strtok illustrates why some C library functions were not written to be thread-safe. strtok, which scans a string to find the next occurrence of a token, maintains persistent state between successive calls to the function, and this state is in static storage, shared by all the threads calling the function.
Microsoft C solves such problems by supplying a thread-safe C library implementation named LIBCMT.LIB. There is more. Do not use CreateThread; rather, use a special C function, _beginthreadex, to start a thread and create thread-specific working storage for LIBCMT.LIB. Use _endthreadex in place of ExitThread to terminate a thread.
Note: There is a _beginthread function, intended to be simpler to use, but it should be avoided. First, _beginthread does not have security attributes or flags and does not return a thread ID. More importantly, it actually closes the thread handle it creates, and the returned thread handle may be invalid by the time the parent thread stores it. Also avoid _endthread; it does not allow for a return value.
The _beginthreadex arguments are exactly the same as for the Windows functions, but without the Windows type definitions; therefore, it is necessary to cast the _beginthreadex return value to a HANDLE to avoid warning messages. Be certain to define _MT before any include files; this definition is included in Envirmnt.h for the sample programs. That is all there is to it. In summary, when you're using the Visual C++ development environment, be sure to do the following:
Link with LIBCMT.LIB and override the default library.
Include #define _MT in all source files that use the C library.
Include <process.h> for the _beginthreadex and _endthreadex definitions.
Create threads with _beginthreadex; do not use CreateThread.
Terminate threads with _endthreadex or simply use a return statement at the end of the thread routine.
Appendix A gives instructions on how to build threaded applications. In particular, it is possible, and recommended, to specify the library and the _MT setting directly from the development environment.
All examples will operate this way, and the programs will never use CreateThread directly, even if the thread functions do not use the C library.
User-developed libraries must be carefully designed to avoid thread safety issues, especially when persistent state is involved. An example in Chapter 12 (Program 12-4), where a DLL maintains state in a parameter, shows one strategy.
Another Chapter 12 example (Program 12-5) demonstrates an alternative approach that exploits the DllMain function and TLS, which is described later in this chapter.