Article ID: 163449 - Last Review: February 21, 2007 - Revision: 4.2 Use of Thread Local Storage in an extended stored procedureThis article was previously published under Q163449 On This PageSUMMARY
Thread Local Storage (TLS) can be a very tricky subject. When working in a
thread pooling environment, it is very important that you understand the
ramifications of TLS and the thread interactions.
It is highly suggested you avoid TLS in a thread pooling environment such as Microsoft SQL Server. However, if you must use TLS, please carefully read this document and consult the online documentation in the Win32 SDK for the TLS and DLL main functions. Also, the compiler directive __declspec(thread) is not supported in an extended stored procedure. When LoadLibarary takes place, the __declspec(thread) definition is not properly initialized. See "Advanced Windows" by Jeffrey Ricter for more details. NOTE: Any extension to SQL Server, including extended stored procedures, may never make a call to DisableThreadLibraryCalls(). MORE INFORMATION
As documented, the TlsAlloc function returns an index value that is used in
function calls to TlsSetValue and TlsGetValue. The documentation suggests
that you call the TlsAlloc function in your DLLMain function when
ul_reason_for_call = DLL_PROCESS_ATTACH. By default, DLL_PROCESS_ATTACH is
called when the DLL is initially loaded.
In DLL_PROCESS_ATTACH and DLL_THREAD_ATTACH, you should allocate memory and call TlsSetValue. This is specifically where the thread pooling starts to cause some problems in the scenario. Below is an example scenario that applies to any application that does thread pooling. This example uses the Microsoft SQL Server application. The following are a few basics for the example that you must understand. These are all documented in more detail in the Win32 SDK documentation under the DLLMain function.
Thread ATTACH CALLED COMMAND USER
------------------------------------------------
1 NO select Joe
2 YES xp_test Mary
3 YES select Adam
1 NO xp_test Lynn
Joe starts a long-running select statement. No one has used the xp_test extended stored procedure yet, so there is no way for the DLL_ATTACH process to be called. While Joe's select is running, Mary runs xp_test. The thread pooling mechanism determines that a new thread should be spawned to service Mary's request. SQL Server then calls the LoadLibrary function to load the Xproc.dll file. In doing so, thread 2 is the first thread to attach to the DLL, so DLL_PROCESS_ATTACH is called. As discussed earlier, TlsAlloc can be called to initialize the extended stored procedure's TLS index value. While Joe's and Mary's commands are running, Adam submits his own select. Again, a new thread is spawned to handle Adam's request. Because thread 3 is spawned after the LoadLibrary took place, thread 3 calls DLL_THREAD_ATTACH. As documented, this is where you would allocate the memory for thread 3 and call TlsSetValue. Now, suppose Joe's select has completed, so worker thread 1 is free for use. Lynn submits the xp_test command, and is assigned thread 1. Thread 1 never calls DLL_PROCESS_ATTACH or DLL_THREAD_ATTACH, because the thread was spawned before the LoadLibrary was called. From this example, you can see that any attempt by thread 1 to access the TLS memory with TlsGetValue results in a NULL pointer being returned. If the extended stored procedure is not properly written to check for this condition, you will encounter an access violation (AV) when you try to write to the NULL address. Below are several points that need to be mentioned about TLS and thread pooling. If you are using TLS in a pooling environment, you must always check the TlsGetValue for a NULL return value. When you get a NULL, you must correctly allocate memory and call TlsSetValue to handle those threads that where spawned before the LoadLibrary took place. Another caveat not directly addressed in the documentation is that you will allocate the TLS memory in the DLLMain function for every thread spawned after the LoadLibarary, even if the thread never uses the functions in the DLL. The example above shows this with thread 3. It only ran a select, but it called DLL_THREAD_ATTACH, which allocated the TLS memory for the extended stored procedure. If you place this design in a thread pooling environment, you may allocate memory that may never be used. The following is the best way to optimize the allocation of memory:
The following is an extended stored procedure that shows the behavior described in the example: MORE INFORMATIONSQL Server 7.0 and SQL Server 2000 FibersWe strongly discourage using TLS and we do not support using TLS in Fiber mode. In Fiber mode, the physical thread can be changed for many reasons, making any TLS unsafe. | Article Translations
|
Back to the top
