我有一个复杂的结构,这不是线程安全修补匠的方法。通常情况下,这是没有问题的,本质上是这种方法的所有调用应该从初始化阶段,这是应该在一个单独的线程来运行(我们已经开始main()
用相同的一种)制成。
然而,它看起来像我的代码库里面的一些恶意组件确实调用从非主线程此方法。我明明可以添加一个互斥/锁后卫这个方法针对潜在呼叫的保障,但是,从我的角度来看,这是一种解决方法,而不是我在寻找一个解决方案。
当然,我还可以添加一个运行时断言,即是这样的:
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看了看,但是如果我在正确的道路上,并且/或者我可以应用它。
你可以做的是建立一些断言宏。用你的线程库来获得线程标识符。保存线程ID第一次你代码会生成一个数据结构。然后声称它每次进入这些功能的时间匹配当前线程ID。
在CEF(铬嵌入式框架)库使用此。
通过包装这些宏像断言,预处理器会将其删除在发布版本是集-DNDEBUG。
如果你曾经获得票友,CEF还具有以下功能:发布和让其他线程可以有工作在UI线程上通过发布一条消息,它做处理消息。
......这种方法的所有调用应该从初始化阶段进行...
忘掉线程。如果功能只是意味着在被称为“初始化”,然后确保它只能在初始化过程中被调用:
boolean initialization_is_complete = false;
problematic_function(...) {
ASSERT(! initialization_is_complete);
...
}
initialize_the_system(...) {
...
call_things_that_call_problematic_function(...);
...
initialization_is_complete = true;
}
断言()在运行时会发生的,对吧?......我想一些静态分析工具能[预防],在编译时。
我不是一个C ++高手。唯一的编译时间的方法,我知道的,以防止“非法”使用任何事情是作出声明private
在编译单元类或static
*如果我能把problematic_function()
是static
编译单元中,其公开符号仅在“初始化”时非常有用,那就是我会做。
在另一方面,如果我的同胞开发商不得不他们为什么要在其他时间致电problematic_function()
,从别的地方很好的理由,那么我会认真考虑重新设计,以便它不会是一个问题。
*如果你把一些constexpr
招或一些template
把戏,我没有想到的(我不是一个C ++专家),那么我敢打赌,它仍然将取决于东西是在范围内的初始化代码的声明,和外的范围为所有其他代码。
让我们再回到原来的想法,这是为了防止任何“错误”的线程调用该函数:所以其实没有这样的事情在C ++语言中的线程。所述std::thread
数据类型由一个库提供,并且编译器本身无法得知螺纹(s)表示,将执行它转换代码的身份的方法。
也就是说,std::this_thread::get_id()
不constexpr
,并没有编译时的方式把它与程序中的任何std::thread
的身份进行比较。
也许有一天,他们会定义std::main_thread
...