【发布时间】:2017-11-01 11:05:38
【问题描述】:
我需要为 Sendmail 开发一个 milter,并且考虑了很长时间我应该使用哪种语言/框架。最后,我决定直接使用 milter API 用纯 C 语言来完成。
我研究了the milter API documentation 并认为我已经掌握了这些概念。但是有一件事情让我非常担心。来自this section:
一个过滤器进程可以处理任意数量的连接 同时。因此,所有过滤回调必须是可重入的, 并使用一些适当的外部同步方法来访问 全球数据 [...]。
虽然我非常理解为什么回调必须是线程安全的,但我不明白为什么它们必须是可重入的。我无法想象可以从中断或信号处理程序中调用这些回调(也许除了中止回调,我将不得不重新阅读此内容)。
要求可重入的问题是可重入函数不能调用不可重入代码。因此,如果回调真的必须是可重入的,我就不能使用malloc() 和那里的大多数其他库函数;来自man 3 malloc:
为避免多线程应用程序损坏,使用互斥锁 在内部保护使用的内存管理数据结构 通过这些功能 [...]
这肯定意味着malloc() 是线程安全的,这可能意味着malloc() 不可重入,因此没有使用它的函数。
所以我有两个问题:
1) milter 回调是否真的需要重入,或者这实际上是 milter API 文档中“需要线程安全”的一个非常奇怪的措辞?
2) 如果他们真的需要重入,我该如何规避上面提到的问题?由于 milter API 的特性,我很难想象如何在不使用malloc() 和其他不可重入库函数的情况下在回调中做一些合理的事情。
【问题讨论】:
-
“这肯定意味着 malloc() 是线程安全的,它可能意味着 malloc() 不是可重入的。”线程安全的东西也可能是可重入的,但不一定反之亦然。想象一个将函数指针传递给函数的单线程应用程序(例如,信号槽概念中的信号处理程序)。这可能会导致重新进入成为问题的情况,尽管线程安全不是一个问题。恕我直言,如果
malloc()被授予线程安全的,我敢打赌它也是可重入的。 -
找到一个很好的问答:SO: Threadsafe vs re-entrant。
-
@Scheff 我相信
malloc()是线程安全的原因是它们使用互斥锁(即一种锁)。我认为malloc()不可重入的原因是他们使用互斥锁(即一种锁)... -
好吧,我按照上面提供的链接重新阅读了一遍。 (当前)last answer 明确区分了线程安全和可重入。以前没见过这么清楚的。因此,我必须承认
malloc()可能是线程安全的,但不一定是可重入的(如果手册中没有说明)。
标签: c sendmail reentrancy milter