代码之家  ›  专栏  ›  技术社区  ›  GreyCat

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

  •  0
  • GreyCat  · 技术社区  · 5 年前

    我有一个方法可以修补一个不安全的复杂结构。通常,这不是问题,因为基本上所有对这个方法的调用都应该从初始化阶段开始,初始化阶段应该在一个线程中运行(我们已经开始的同一个线程) main() 与)。

    然而,看起来我的代码库中的一些恶意组件确实在从非主线程调用此方法。显然,我可以在这个方法中添加一个mutex/lock保护来防止潜在的调用,但是,从我的角度来看,这只是一个解决方案,而不是我要寻找的解决方案。

    当然,我也可以添加运行时断言,例如:

    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);
    }
    

    ... 但这不能保证。

    问题:

    我已经看过了 assert-like contracts 在C++ 20中,但是如果我在正确的路径上,或者我可以应用它。

    2 回复  |  直到 5 年前
        1
  •  3
  •   Zan Lynx    5 年前

    你能做的就是建立一些断言宏。使用线程库获取线程标识符。在代码第一次构建数据结构时保存线程ID。然后在每次输入这些函数时断言它与当前线程ID相匹配。

    CEF(Chromium-Embedded Framework)库使用这个。

    通过像断言一样包装这些宏,预处理器将在设置了-DNDEBUG的发布版本中删除它们。

    如果您曾经有过发烧友,CEF也有一些函数来发布和处理消息,这样其他线程就可以通过向UI线程发布消息来完成对UI线程的工作。

        2
  •  2
  •   Solomon Slow    5 年前

    …对该方法的所有调用都应从初始化阶段开始。。。

    别管螺纹了。如果只在“初始化”期间调用该函数,请确保它只能在初始化期间调用:

    boolean initialization_is_complete = false;
    
    problematic_function(...) {
        ASSERT(! initialization_is_complete);
        ...
    }
    
    initialize_the_system(...) {
        ...
        call_things_that_call_problematic_function(...);
        ...
        initialization_is_complete = true;
    }
    

    ASSERT()将在运行时发生,对吗?。。。我希望一些静态分析工具能够在编译时[防止]这种情况发生。

    我不是C++专家。我只知道“未经授权”的“时间”的声明 private 对一个班级或 static 如果我能 problematic_function() 静止的 在一个公共符号只在“初始化”时有用的编译单元中,我会这样做。

    有问题的函数() 在其他地方,我会认真考虑,在其他地方,这不是一个问题。


    *如果你拉一些 constexpr template 我没想到的把戏 一个C++专家,那么我敢打赌,它仍然依赖于声明 某物 这在init代码的作用域内,而在所有其他代码的作用域之外。


    std::thread 数据类型是由库提供的,编译器本身无法知道将要执行其转换的代码的线程的标识。

    也就是说, std::this_thread::get_id() 不是 常量表达式 ,而且没有 把它和任何 标准::螺纹 在节目里。

    也许有一天他们会定义 std::main_thread ...