Example: An Alternative Thread-Safe DLL Strategy
Program 12-4, while typical of the way in which TLS and DllMain are combined to create thread-safe libraries, has a weakness that is noted in the comments in the previous section. In particular, the "state" is associated with the thread rather than with the socket, so a given thread can process only one socket at a time.An effective alternative approach to thread-safe library functions is to create a handle-like structure that is passed to every function call. The state is then maintained in the structure. Many UNIX systems use this technique to create thread-safe C libraries; the main disadvantage is that the functions require an additional parameter for the state structure.Program 12-4. Notice that DllMain is not necessary, but there are two new functions to initialize and free the state structure. The send and receive functions require only minimal changes. An associated server, serverSKHA, is included on the book's Web site and requires only slight changes in order to create and close the socket handle (HA denotes "handle").
Program 12-5. SendReceiveSKHA: Thread-Safe DLL with a State Structure
/* SendReceiveSKHA.c -- multithreaded streaming socket. */
/* This is a modification of SendReceiveSKST.c to illustrate a */
/* different thread-safe library technique. */
/* State is preserved in a HANDLE-like state structure rather than */
/* using TLS. This allows a thread to use several sockets at once. */
/* Messages are delimited by end-of-line characters ('\0'). */
#define _NOEXCLUSIONS
#include "EvryThng.h"
#include "ClntSrvr.h " /* Defines the request and response records. */
typedef struct SOCKET_HANDLE_T {
/* Current socket state in a "handle" structure. */
/* Structure contains "static_buf_len" characters of
residual data. */
/* There may or may not be end-of-string (null) characters. */
SOCKET sk; /* Socket associated with this "handle." */
char static_buf [MAX_RQRS_LEN];
LONG32 static_buf_len;
} SOCKET_HANDLE, * PSOCKET_HANDLE;
/* Functions to create and close "streaming socket handles." */
_declspec (dllexport)
PVOID CreateCSSocketHandle (SOCKET s)
{
PVOID p;
PSOCKET_HANDLE ps;
p = malloc (sizeof (SOCKET_HANDLE));
if (p == NULL) return NULL;
ps = (PSOCKET_HANDLE) p;
ps->sk = s;
ps->static_buf_len = 0; /* Initialize buffer state. */
return p;
}
_declspec (dllexport)
BOOL CloseCSSocketHandle (PVOID p)
{
if (p == NULL) return FALSE;
free (p);
return TRUE;
}
_declspec (dllexport)
BOOL ReceiveCSMessage (REQUEST *pRequest, PVOID sh)
/* Use PVOID so that calling program does not need to include */
/* the SOCKET_HANDLE definition. */
{
/* TRUE return indicates an error or disconnect.
... */
PSOCKET_HANDLE p;
SOCKET sd;
p = (PSOCKET_HANDLE) sh;
if (p == NULL) return FALSE;
sd = p->sk;
/* This is all that's changed from SendReceiveSKST!
... */
}
_declspec (dllexport)
BOOL SendCSMessage (RESPONSE *pResponse, PVOID sh)
{
/* Send the request to the server on socket sd.
... */
SOCKET sd;
PSOCKET_HANDLE p;
p = (PSOCKET_HANDLE) sh;
if (p == NULL) return FALSE;
sd = p->sk;
/* That's all that's changed from SendReceiveSKST!
... */
}
