Safe static destructors when multiple threads call exit ()

How to safely remove C ++ static objects when multiple (Posix) threads call exit() in parallel?

In my CentOS6 environment, exit() appears, executing atexit (or on_exit ) cleanup handlers, calling something like fct[--cnt]() , where cnt is the number of registered handlers. When several exit() threads are called at the same time, we have a race condition in the insecure operation --cnt , and some handlers may be skipped or called several times (which leads to an accidental failure). So, how can I guarantee that only one of the exit() threads causes a cleanup and all the rest? Note that inserting pthread_mutex_lock() into the cleanup handler does not help, because this handler may be skipped ...

Unfortunately, I cannot avoid having multiple threads call exit() , because this code will be written by my users (I provide them with a library).

Looking for safe ideas, thanks!

+5
source share
2 answers

There is no portable way to handle multiple calls to exit () - because this is undefined (behavior), which happens in this case.

But for a specific platform, you can find a way to do this. A somewhat common solution for โ€œcalled multiple timeโ€ is to have a flag in your static objects, such as โ€œI'm already destroyed.โ€ As usual, you can hide this in the template:

 template <typename T> class StaticExitHandled { public: std::unique_ptr<T> t_; ~StaticExitHandled() { t_.release(); } }; 

Now just remember the declaration of all your static objects with this template. This is just the gist of this, add the bells and whistles to your liking. Alternatively, instead of std :: unique_ptr <> you can use boost :: optional <> or some such things.

I do not think there is a general solution for "not called at all."

Actually, I would advise not to have non-trivial static objects in a multi-threaded environment. Thus, there are only static PODs and objects with very limited destructors (depending on what is safe to do at this point in your environment, that is, closing file descriptors is okay in most cases).

+1
source

If you are using gcc, you can use the following code to define the cleanup procedure:

 void __attribute__ ((destructor)) my_fini(void); 

If this does not solve your problem, how about defining a single object with a static duration, whose destructor will take care of your cleaning?

0
source

Source: https://habr.com/ru/post/1206117/


All Articles