__attribute__((constructor)) 是不是保证只被调用一次?
Posted
技术标签:
【中文标题】__attribute__((constructor)) 是不是保证只被调用一次?【英文标题】:Is __attribute__((constructor)) guaranteed to be called exactly once?__attribute__((constructor)) 是否保证只被调用一次? 【发布时间】:2014-08-28 00:36:00 【问题描述】:使用__attribute__((constructor))
和__attribute__((destructor))
定义的GCC 共享库构造函数和析构函数是否保证只运行一次?该文档似乎暗示它们将至少运行一次,但没有提到任何关于不止一次的内容。
换句话说,如果我在构造函数中做了一个只能执行一次的操作,我是否需要像这样保护它:
static gboolean constructor_has_run = FALSE;
if(!constructor_has_run)
do_operation();
constructor_has_run = TRUE;
【问题讨论】:
在实践中,我认为这总是可以保证的,但如果 GCC 能更好地记录这一点,那就太好了。 是 - 构造函数在 main() 之前调用一次,析构函数在之后调用一次。 在简单的情况下很明显,但在dlopen
情况下就变得不那么简单了。
它被称为“构造函数”,而不是“被称为未指定正数的函数”。后者不是构造函数通常所做的。意图一清二楚。如果您认为应该在文档中明确提及,请针对文档提交错误。
@n.m.:加载一个库而不先卸载它是合法的。在 Windows 下,每次加载库时,为每个线程调用一次DLLMain
。 _init
保证在 Linux 下只被调用一次,但不一定对每个系统都如此。尽管如此,在 GCC 下,构造函数(分别从 DLLMain
和 _init
调用)只运行一次。无论你做什么,无论我尝试过什么系统。
【参考方案1】:
如果有人想在标头中使用此类函数,可能会有用的观察:如果函数被定义为
__attribute__((constructor)) inline void fn()
...
在N个翻译单元中,会被调用N次。
【讨论】:
【参考方案2】:如果你使用__attribute__((constructor))
,它将在执行开始时被调用。
所以你不必像上面提到的那样保护。
如果你也提到它没有错
有关__attribute__((constructor))
的更多信息,您可以查看https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
【讨论】:
【参考方案3】:花了一些时间调试我在析构函数中看到的一些异常行为后,这里的答案是“视情况而定”。
在正常情况下,构造函数和析构函数只会被调用一次。但是,当涉及到共享库时,构造函数和析构函数可能会被多次调用。
我正在进行一些单元测试,并直接与包含构造函数的模块进行静态链接。该链接还引入了共享库,这些库最终会加载驻留在依赖共享库上下文中的模块的第二个副本。
结果是构造函数和析构函数针对位于 main() 映像中的模块版本调用一次,并且针对已加载共享库中的模块版本调用一次。
【讨论】:
以上是关于__attribute__((constructor)) 是不是保证只被调用一次?的主要内容,如果未能解决你的问题,请参考以下文章
__attribute__ ((__packed__)); 怎么用?
GCC的__attribute__ ((constructor))和__attribute__ ((destructor))