简体   繁体   English

C ++:确保在编译时仅在指定线程上调用该函数

[英]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). 通常,这不是问题,因为对该方法的基本上所有调用都应在初始化阶段进行,该阶段应该在单个线程中运行(与我们以main()开始的线程相同)。

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. 我已经研究过C ++ 20中类似断言的合同 ,但是如果我走对了路和/或可以采用它。

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. 在您的代码首次构建该数据结构时,请保存线程ID。 Then assert it matches the current thread ID every time you enter those functions. 然后,在每次输入这些功能时断言它与当前线程ID匹配。

The CEF (Chromium Embedded Framework) library uses this. CEF(铬嵌入式框架)库使用此库。

By wrapping these macros up like asserts, the preprocessor will remove them in release builds that set -DNDEBUG. 通过像断言一样包装这些宏,预处理器将在设置-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. 如果您不得不变得更高级,CEF还具有发布和处理消息的功能,以便其他线程可以通过向其发布消息来在UI线程上完成工作。

...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. ASSERT()会在运行时发生,对吧?...我希望有一些静态分析工具能够在编译时[防止]这样做。

I am not a C++ expert. 我不是C ++专家。 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. 我所知道的防止“未经授权”使用任何东西的唯一编译时方法是将其声明对某个类或编译单元中的static private 。*如果我可以使problematic_function()在编译单元中为static其公共符号仅在“初始”时间才有用,这就是我要做的。

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. 另一方面,如果我的开发人员有充分的理由为什么要在其他时间从其他地方调用problematic_function() ,那么我将认真考虑重新设计它,这样就不会出现问题。


* 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. *如果您拉出一些我没想到的constexpr技巧或template技巧(我不是 C ++专家),那么我敢打赌,它仍将依赖于init代码范围内的某种声明,并超出所有其他代码的范围。


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. 回到您最初的想法,即防止任何“错误的”线程调用该函数:实际上,没有C ++语言中的线程之类的东西。 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. std::thread数据类型由库提供,并且编译器本身无法知道将执行其转换后的代码的线程的标识。

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. 也就是说, std::this_thread::get_id()不是constexpr ,并且没有编译时方法可以将它与程序中任何std::thread的标识进行比较。

Maybe some day they'll define std::main_thread ... 也许有一天他们会定义std::main_thread ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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