我需要为Sendmail开发一个milter,并且已经考虑了很长时间应该使用哪种语言/框架。最后,我决定直接使用milter API在普通C中实现它。
我已经学习了milter API文档,并且认为我已经掌握了这些概念。但有一件事让我非常担心。来自本节:
单个筛选器进程可以处理任意数量的连接同时因此,所有过滤回调都必须是可重入的,并使用一些适当的外部同步方法来访问全球数据〔…〕.
虽然我非常理解为什么回调必须是线程安全的,但我无法理解为什么它们必须是可重入的。我无法想象这些回调可以从中断或信号处理程序调用(也许除了中止回调,我必须重新阅读)。
要求可重入的问题是,可重入函数不能调用非可重入代码。因此,如果回调真的必须是可重入的,我就不能在那里使用malloc()
和大多数其他库函数;来自man 3 malloc
:
为了避免多线程应用程序中的损坏,使用了互斥内部保护所采用的内存管理数据结构通过这些功能〔…〕
这当然意味着malloc()
是线程安全的,它可能意味着malloc()
不是可重入的,因此没有使用它的函数。
所以我有两个问题:
1) milter回调真的需要重新集中吗?或者这实际上是milter API文档中"需要线程安全"的一个非常奇怪的措辞吗?
2) 如果他们真的需要重新加入,我该如何规避上述问题?由于milter API的特性,如果不使用malloc()
和其他非集中式库函数,我很难想象如何在回调中做一些合理的事情。
在Milter-API的上下文中(它还强调它在内部使用posix线程),"可重入"函数被定义为可以同时从多个线程安全执行的函数。这意味着不屈服于种族条件。
术语"可重入"的用法与其他UNIX/Linux API文档(如strtok
:)一致
strtok_r()
函数是strtok()
的可重入版本。[..]┌───────────┬───────────────┬───────────────────────┐ │Interface │ Attribute │ Value │ ├───────────┼───────────────┼───────────────────────┤ │strtok() │ Thread safety │ MT-Unsafe race:strtok │ ├───────────┼───────────────┼───────────────────────┤ │strtok_r() │ Thread safety │ MT-Safe │ └───────────┴───────────────┴───────────────────────┘
另请参阅其他*_r()
函数,如ctime_r()
、gmtime_r()
等。