我刚刚读到 complexities of environ
特别是它是多么线程不安全,因为它对 assign to it 是合法的。替换整个环境。
考虑到这一点,是否有任何类型的 API 可以迭代所有当前环境变量,但不直接使用静态 environ
数组?
需要明确的是,我知道 getenv()
, setenv()
和 friend 们(关于 putenv()
说得越少越好)——这些只允许恢复特定变量,而不是迭代所有变量。
我还编写了大量直接迭代environ
的代码。但令我震惊的是,在任何合理的多线程应用程序中,使用环境的唯一明智的方法是尽早在 main()
中插入代码,将其放入 unordered_map
中。或类似的并且只能从那里使用它;或者只是将其视为完全不可变,并希望链接库中没有人这样做。
所以我想知道是否有任何更安全的接口(interface)被定义为 POSIX 的一部分,或者可能是特定于平台的,而我不知道?
最佳答案
在多线程应用程序中,使用环境的唯一明智方法是将其视为只读。如果需要修改它,应该在程序初始化阶段、启动任何线程之前进行修改。
由于环境的目的是从环境到应用程序进行通信,因此将环境视为只读应该不成问题。与此用例一致,除了使用 environ 之外,没有用于迭代环境的标准接口(interface),并且不能在多线程应用程序中安全使用,除非应用程序 promise 不修改环境.
据我所知,没有标准库函数会修改环境(除了 setenv
和 putenv
之外),而且 IMO 也没有哪个健全的库会这样做。
人们认识到,有时需要修改环境,要么引入默认值,要么作为 fork 子项初始化序列的一部分。在前一种情况下,通常可以在启动线程之前如上所述执行修改。
后一种情况在多线程应用程序中很棘手,但无论如何,仅在子级中修改环境就很容易了(即在调用 fork()
之后和调用之前) exec*()
。或者,可以构建一个全新的环境并将其提供给接受环境参数的 exec()
版本。
简而言之,使用环境作为全局变量的替代品甚至比首先使用全局变量更糟糕(恕我直言)。但是,将其用于其发明目的(由父进程配置子进程)不会引起问题。
在评论中进行了有趣的讨论之后,似乎值得添加一些注释。
首先,许多标准(和非标准)库函数读取环境。这对于调试来说特别方便,但它也用于许多配置选项,包括执行路径搜索、区域设置、控制台窗口大小、时区等等(在 Base 中有一个很长但不完整的列表) Posix 标准的定义卷。)
由于 getenv
不能在多线程代码中安全使用,除非知道不能对环境进行并发修改,因此禁止标准库函数修改环境似乎是合理的(除了为此类修改而设计的接口(interface))。据我所知,Posix 不包含此禁令,但它确实要求所有接口(interface)记录其对环境的使用,并且我不相信我见过除 putenv
之外的任何接口(interface),setenv
和 unsetenv
已记录用于修改环境。总的来说,我认为假设线程启动后多线程代码中的环境不会被修改是完全合理的(甚至是必要的)。
当然,在单线程代码中或多线程代码中在启动线程之前修改环境是合法的。但最佳实践表明只能使用两种可能的修改机制之一:
setenv
(和unsetenv
)接口(interface)。- 将
environ
直接分配给另一个数组,其中原始environ
中存在的任何字符串都已复制到应用程序管理的内存中。
使用 putenv
确实不可取,但只要它不与上面的其他两种可能性混合,它是可以接受的。
再次强调,Posix 不提供限制、指南或建议(除了更喜欢 setenv
而不是 putenv
),因此请将以上内容作为我的建议。
关于c++ - 是否有迭代 POSIX 环境变量的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29215886/