0

In WinAPI you can create and access thread local storage using functions such as TlsAlloc, TlsGetValue, TlsSetValue and TlsFree. The API supposes that you will store pointers in the thread local storage (for sure you can store size_t integers casted to pointers, but often we would like to store more information). So, probably this memory will be allocated by every thread which uses this data. But the problem is how to free this memory at thread exit.

In pthreads you have an optional destructor argument for pthread_key_create function (pthreads version of TlsAlloc). But in raw WinAPI TlsAlloc doesn't provide such option. How to implement a custom destructor for thread local storage using only WinAPI and plain C (so no modern C++ thread local storage which supports object destructors on the compiler level)?

I'm writing a normal program, not a DLL, so I don't care about the corner case "DLL unloaded before program exit, so the destructor code became unavailable". I think, I am looking for a function similiar to atexit, but on thread level.

6
  • There isn't any OS-supported way of calling a function at thread exit. Best you can do is to make all your threads use a common entry point, that manages the lifetime of the thread-local data and then invokes the real thread entry point. Commented Dec 8, 2022 at 19:34
  • @JonathanPotter "There isn't any OS-supported way of calling a function at thread exit" - actually, there is. A FlsAlloc() callback is called at thread exit. See Fibers aren’t useful for much any more; there’s just one corner of it that remains useful for a reason unrelated to fibers Commented Dec 8, 2022 at 19:49
  • @JonathanPotter There are at least one alternative - I can add a TLS object to linked list and also add duplicated current thread handle to my TLS struct. Then create a thread which iterates over the list every few seconds and try to do WaitObject with zero timeout on every thread handle. If WaitObject success then you can remove object from the list, close thread handle and free the object. Commented Dec 8, 2022 at 20:21
  • If you do not explicitly exit any threads, then all these kinds of destruction/deallocation just...disappear:) Commented Dec 8, 2022 at 21:21
  • ...so, if you use only process-lifetime threads, eg pools created once at startup, you will not need to design, develop, test and debug any such destructor code every time you release a new version or deploy to a new OS. Commented Dec 8, 2022 at 21:26

1 Answer 1

5

On Windows Vista+, if you switch to fiber-local storage (FLS) instead of thread-local storage (TLS), you can then use FlsAlloc() to register a callback function that can be called at thread exit.

PFLS_CALLBACK_FUNCTION callback function

An application-defined function. If the FLS slot is in use, FlsCallback is called on fiber deletion, thread exit, and when an FLS index is freed. Specify this function when calling the FlsAlloc function. The PFLS_CALLBACK_FUNCTION type defines a pointer to this callback function. FlsCallback is a placeholder for the application-defined function name.

See Raymond Chen's article: Fibers aren’t useful for much any more; there’s just one corner of it that remains useful for a reason unrelated to fibers

But there’s still one part of Windows fibers that is still useful: The fiber destruction callback.

...

The callback function is called when a fiber is destroyed. This is the fiber equivalent of DLL_THREAD_DETACH, except that it’s not just for DLLs. Executables can use it too.

Even better: When you deallocate the fiber-local storage slot, the callback is invoked for every extant fiber. This lets you clean up all your per-fiber data before it’s too late.

...

Even though fibers are basically dead, you can use fiber-local storage to get an improved version of thread-local storage.

If you don't create multiple fibers per thread, FLS will act the same as TLS, but you will get the added benefit of the destruction callback.

Sign up to request clarification or add additional context in comments.

2 Comments

Sounds cool. Do I need to create a fiber in every thread which needs TLS or it will work out of the box?
@kiv_apple - no, not need. this work without fibers too.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.