简体   繁体   中英

C++: ensure in compile-time that function is only called on a specified thread

I have a method which tinkers with a complex structure that's not thread-safe. Normally, this is not a problem, as essentially all calls to this method should be made from initialization phase, which is supposed to be running in a single thread (the same one that we've started main() with).

However, it looks like some malicious component inside my codebase is indeed calling this method from non-main thread. I obviously can add a mutex/lock guard into this method as a safeguard against potential calls, but, from my perspective, this is a workaround, not a solution I'm looking for.

Of course, I can also add a runtime assert, ie something like:

static std::thread::id s_main_thread_id

int main(...) {
    s_main_thread_id = std::this_thread::get_id();
    // ...
}

void vulnerable_function() {
    ASSERT(std::this_thread::get_id() == s_main_thread_id);
}

... but that's not a guarantee.

Question: is it possible somehow to assert in compile-time that a certain method should be only ran from a certain (ie main) thread? I'd like to find rogue calls in my codebase and prevent that from happening again.

I've looked through assert-like contracts in C++20, but if I'm on the right path and/or I can apply it.

What you can do is build some assert macros. Use your thread library to get thread identifiers. Save the thread ID the first time your code builds that data structure. Then assert it matches the current thread ID every time you enter those functions.

The CEF (Chromium Embedded Framework) library uses this.

By wrapping these macros up like asserts, the preprocessor will remove them in release builds that set -DNDEBUG.

If you ever had to get fancier, CEF also has functions to post and handle messages so that other threads can have work done on the UI thread by posting a message to it.

...all calls to this method should be made from initialization phase...

Forget about threads. If the function is only meant to be called during "initialization," then make sure that it can only be called during initialization:

boolean initialization_is_complete = false;

problematic_function(...) {
    ASSERT(! initialization_is_complete);
    ...
}

initialize_the_system(...) {
    ...
    call_things_that_call_problematic_function(...);
    ...
    initialization_is_complete = true;
}

The ASSERT() will happen in run-time, right?... I want some static analysis tool to be able [prevent] that at compile-time.

I am not a C++ expert. The only compile-time ways that I know of to prevent the "unauthorized" use of any thing is to make its declaration private to a class or static in a compilation unit.* If I could make problematic_function() be static in a compilation unit whose public symbols are only useful at "init" time, then that's what I would do.

On the other hand, if my fellow developers had good reasons why they wanted to call problematic_function() at other times, from other places, then I would seriously consider re-designing it so that it would not be a problem.


* If you pull some constexpr trick or some template trick that I didn't think of (I am not a C++ expert), then I bet that it still will depend on a declaration of something that is in-scope for the init code, and out-of-scope for all the other code.


Going back to your original idea, which was to prevent any "wrong" threads from calling the function: There actually is no such thing as a thread in the C++ language. The std::thread data type is provided by a library, and the compiler itself has no way of knowing the identity of the thread(s) that will execute the code that it translates.

That is to say, std::this_thread::get_id() is not constexpr , and there is no compile-time way to compare it with the identity of any std::thread in the program.

Maybe some day they'll define std::main_thread ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM