毫无问题的回调真的需要重新进入吗?

时间:2017-11-01 11:05:39

标签: c sendmail reentrancy milter

我需要为Sendmail开发一个milter并且已经考虑了很长时间我应该使用哪种语言/框架。最后,我决定直接使用milter API在普通C中完成它。

我研究过the milter API documentation并认为我已经掌握了这些概念。但是有一件事让我很担心。来自this section

  

单个过滤器进程可以处理任意数量的连接   同时。因此,所有过滤回调必须是可重入的,   并使用一些适当的外部同步方法来访问   全球数据[...]。

虽然我很清楚为什么回调必须是线程安全的,但我无法理解为什么它们必须是可重入的。我无法想象那些回调可以从中断或信号处理程序调用(可能除了中止回调,我将不得不重新读取它)。

要求可重入的问题是重入函数不能调用不可重入的代码。因此,如果回调真的必须重入,我就不能在那里使用man 3 malloc和大多数其他库函数;来自malloc()

  

为避免多线程应用程序中的损坏,使用互斥锁   内部保护所采用的内存管理数据结构   通过这些功能[...]

这肯定意味着malloc()是线程安全的,这可能意味着malloc()不是可重入的,因此没有使用它的函数。

所以我有两个问题:

1)milter回调是否真的需要重入,或者这实际上是milter API文档中“需要线程安全”的非常奇怪的措辞?

2)如果他们真的需要重新进入,我怎样才能规避上述问题?由于milter API的特性,我很难想象如何在不使用[Route("api/tickets")] public HttpResponseMessage Post([FromBody]JObject newTicket) { var t = newTicket.ToObject<Ticket>(); TicketsRepository.InsertTicket(t); HttpResponseMessage = Request.CreateResponse(HttpStatusCode.OK); return response; } 和其他非重入库函数的情况下在回调中做一些合理的事情。

1 个答案:

答案 0 :(得分:0)

在 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() 等。