Use thread_local instead of static in EASY_LOCAL_STATIC_PTR. #130
Use thread_local instead of static in EASY_LOCAL_STATIC_PTR. #130madevgeny wants to merge 5 commits intoyse:developfrom
Conversation
…ut it it's impossible to profile functions called from multiple threads.
|
Hi |
I use visual studio 2015. I have the following case: void ed::PoolTask::run() Which is called from many threads. So if you use static variable it'll be changed in the middle of profiling. It appears under relatively heavy load. |
|
I think this issue isn't compiler specific. |
|
C++11 standard guarantees that local static initialization is thread-safe. And this static in I think your problem is related to the usage of |
|
For example: void ed::PoolTask::run()
{
const std::string local_id = id; // try to use temporary buffer
EASY_BLOCK(local_id.c_str());
func();
// EASY_END_BLOCK; // this is not necessary because EASY_BLOCK using RAII
} |
|
Hi @madevgeny |
|
Hi, it appears that we use /Zc:threadSafeInit- flag which disables thread safe statics. We need it for our protection system and unfortunately we will not be able to change it in near future. I attached simple example to reproduce crash. But with my patch it works without crash. Another thought. EASY_BLOCK unrolls to something like this: static const ::profiler::BaseBlockDescriptor* desc = ::profiler::registerDescription("unique arguments"); if we call the same function from multiple threads but with different "unique arguments" we will write to desc pointers to different objects. So there is no guarantee that after writing pointer to desc we will have read the same pointer from it. As static variable desc can be changed from other threads. tread_local solves this problem too. |
No, id is member of PoolTask class. |
Well, this explains the problem :-) If this flag could be checked at compile-time in source code then the fix will be: #ifndef EASY_LOCAL_STATIC_PTR
# if defined(_MSC_VER) && defined(_MSC_ZC_THREAD_SAFE_INIT) // Something like this
# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer) thread_local static VarType ...
# else // This is existing branch:
# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer) static VarType ...
# define EASY_MAGIC_STATIC_AVAILABLE
#endifIf it's impossible to check the flag in source code then you will have to add new CMake option into |
|
It would be great if you could fix it :-) |
…As without it it's impossible to profile functions called from multiple threads." This reverts commit 3ee2067.
|
There is no macros to detect /Zc:threadSafeInit- at compile time. I'll add option to easy_profiler_core/CMakeLists.txt. |
…safe initialization of static local variables.
…in project using profiler. EASY_OPTION_THREAD_SAFE_INIT doesn't require setting it in project using profiler.
|
Hi, I added EASY_OPTION_THREAD_SAFE_INIT option and generation of config header. |
| # define EASY_MAGIC_STATIC_AVAILABLE | ||
| # if defined(_MSC_VER) && EASY_DISABLE_THREAD_SAFE_INIT != 0 | ||
| # define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer) thread_local static VarType VarName = VarInitializer | ||
| # define EASY_MAGIC_STATIC_AVAILABLE |
There was a problem hiding this comment.
EASY_MAGIC_STATIC_AVAILABLE should not be defined if thread-safe static init is disabled
| set(EASY_DISABLE_THREAD_SAFE_INIT 1) | ||
| endif () | ||
|
|
||
| configure_file ( |
There was a problem hiding this comment.
Could you, please, use existing easy_define_target_option cmake command instead of generating new file?
|
Is it true that this PR addresses a critical multuthreading usability issue? |
Hi, please look at my changes, without them it's impossible to profile functions called from multiple threads.