Emp*_*ian 96
问题:"是malloc reentrant"吗?
答:不,不是.以下是使例程重入的定义.
malloc的常见版本都不允许您重新输入它(例如,来自信号处理程序).请注意,重入例程可能不使用锁,并且现有的几乎所有malloc版本都使用锁(这使它们成为线程安全的)或全局/静态变量(这使得它们线程不安全且不可重入).
到目前为止,所有的答案都回答"是malloc线程安全吗?",这是一个完全不同的问题.对于这个问题,答案是它取决于你的运行时库,也可能取决于你使用的编译器标志.在任何现代UNIX上,默认情况下您将获得一个线程安全的malloc.在Windows中,使用/MT,/MTd,/MD或/MDd标志来获得线程安全的运行时库.
Tom*_*Tom 44
我在某处读到,如果使用-pthread进行编译,malloc将成为线程安全的.我很确定它的实现依赖,因为malloc是ANSI C而线程不是.
如果我们正在谈论gcc:
在x86和AMD64上编译和链接-pthread和malloc()将是线程安全的.
另一种意见,更有见地
glibc-2.2 +的{malloc,calloc,realloc,free,posix_memalign}是线程安全的
http://linux.derkeiler.com/Newsgroups/comp.os.linux.development.apps/2005-07/0323.html
lik*_*ern 11
这是一个非常古老的问题,我希望根据当前的状况带来新鲜感.
是的,目前malloc()是线程安全的.
从GNU C库参考手册的glibc-2.20 [released 2014-09-07]:
void * malloc (size_t size)初步:MT-Safe | ...
...... 1.2.2.1 POSIX安全概念:
... MT-Safe或线程安全功能可以在其他线程存在的情况下安全地调用.在MT-Safe中,MT代表Multi Thread.
MT-Safe并不意味着函数是原子的,也不是它使用POSIX向用户公开的任何内存同步机制.甚至可能按顺序调用MT-Safe功能也不会产生MT-Safe组合.例如,让一个线程一个接一个地调用两个MT-Safe函数并不能保证等同于两个函数组合的原子执行的行为,因为其他线程中的并发调用可能以破坏性方式干扰.
可以跨库接口内联函数的整个程序优化可能会暴露不安全的重新排序,因此不建议在GNU C库接口上执行内联.在全程序优化下,无法保证记录的MT安全状态.但是,用户可见标头中定义的功能旨在安全地进行内联.
是的,在POSIX.1-2008 下malloc是线程安全的.
2.9.1线程安全
本卷POSIX.1-2008定义的所有函数都应是线程安全的,但以下函数1不必是线程安全的.
[不包含的功能列表
malloc]
如果您使用的是GLIBC,答案是:是的,但是。
具体来说,是的,但是请注意,尽管malloc和free是线程安全的,但调试功能不是。
特别是,极其有用的mtrace(),mcheck()和mprobe()函数不是线程安全的。您将从GNU项目中看到的最短,最直接的答案之一,在此进行解释:
https://sourceware.org/bugzilla/show_bug.cgi?id=9939
您将需要考虑其他技术,例如ElectricFence,valgrind,dmalloc等。
因此,如果您的意思是“ malloc()和free()函数是线程安全的”,答案是肯定的。但是,如果您的意思是“整个malloc / free 套件都是线程安全的”,答案是否定的。
简短回答:是的,从 C11 开始,这是包含线程概念的 C 标准的第一个版本,malloc并且要求朋友是线程安全的。许多同时包含线程和 C 运行时的操作系统早在 C 标准之前就做出了这一保证,但我不准备向所有人发誓。然而,malloc和朋友不是也从来没有被要求可重入。
这意味着,同时从多个线程调用malloc和是安全的,free而不必担心锁定,只要您不违反任何其他内存分配规则(例如free,对由 返回的每个指针仅调用一次malloc)。但它是不是安全的,从可能已中断的呼叫信号处理程序调用这些函数malloc或free在线程处理信号。有时,使用 ISO C 以外的功能,您可以保证处理信号的线程不会中断对mallocor的调用free,例如使用sigprocmaskand sigpause,但除非您没有其他选择,否则尽量不要这样做,因为很难做到完全正确。
带引文的长答案:C 标准在2011 年修订版中添加了线程的概念(链接到文档 N1570,这是与 2011 年标准的官方文本最接近的免费公开文本)。在该修订版中,第 7.1.4 节第 5 段规定:
除非在下面的详细描述中另有明确说明,库函数应防止数据竞争如下: 库函数不应直接或间接访问当前线程以外的线程可访问的对象,除非这些对象是通过函数的参数直接或间接访问的. 除非通过函数的非常量参数直接或间接访问对象,否则库函数不应直接或间接修改当前线程以外的线程可访问的对象。如果对象对用户不可见并且受到保护以防止数据竞争,则实现可以在线程之间共享它们自己的内部对象。
[脚注:这意味着,例如,在没有同步的情况下,不允许实现将静态对象用于内部目的,因为即使在未在线程之间显式共享对象的程序中,它也可能导致数据竞争。同样,不允许 memcpy 的实现复制超出目标对象指定长度的字节,然后恢复原始值,因为如果程序在线程之间共享这些字节,则可能会导致数据竞争。]
据我了解,这是一种冗长的说法,要求 C 标准定义的库函数是线程安全的(通常意义上:您可以同时从多个线程调用它们,而无需自己进行任何锁定) ,只要它们最终不会与作为参数传递的数据发生冲突),除非特定函数的文档明确指出它不是。
然后,7.22.3p2确认 malloc、calloc、realloc、aligned_alloc 和 free 是线程安全的:
为了确定数据竞争的存在,内存分配函数的行为就好像它们只访问可通过其参数访问的内存位置而不是其他静态持续时间存储。然而,这些函数可以明显地修改它们分配或解除分配的存储。释放内存区域 p 的 free 或 realloc 调用与分配全部或部分区域 p 的任何分配调用同步。这种同步发生在解除分配函数对 p 的任何访问之后,并且在分配函数进行任何此类访问之前。
对比它在7.24.5.8p6 中关于 strtok 的说法,它不是也从来不是线程安全的:
不需要 strtok 函数来避免与 strtok 函数的其他调用发生数据竞争。
[脚注:可以使用 strtok_s 函数来避免数据竞争。]
(注释脚注:不要使用strtok_s,使用strsep。)
旧版本的 C 标准对线程安全没有任何说明。然而,他们确实谈到了可重入性,因为信号一直是 C 标准的一部分。这就是他们所说的,回到最初的1989 年 ANSI C 标准(该文件的措辞与次年发布的 ISO C 标准几乎相同,但章节编号非常不同):
如果 [a] 信号发生而不是调用 abort 或 raise 函数的结果,则如果信号处理程序调用标准库中除信号函数本身之外的任何函数或引用具有静态存储持续时间之外的任何对象,则行为未定义而不是通过为 volatile sig_atomic_t 类型的静态存储持续时间变量赋值。此外,如果对信号函数的此类调用导致 SIG_ERR 返回,则 errno 的值是不确定的。
这是说,C库函数的长篇大论方式不为可重入作为一般规则要求。非常相似的措辞仍然出现在 C11, 7.14.1.1p5 中:
如果 [a] 信号发生而不是调用 abort 或 raise 函数的结果,如果信号处理程序引用任何具有静态或线程存储持续时间的对象,并且不是无锁原子对象,则该行为是未定义的,而不是通过赋值声明为 volatile sig_atomic_t 的对象的值,或者信号处理程序调用标准库中除 abort 函数、_Exit 函数、quick_exit 函数或第一个参数等于对应的信号编号的信号函数之外的任何函数导致调用处理程序的信号。此外,如果对信号函数的此类调用导致 SIG_ERR 返回,则 errno 的值是不确定的。
[脚注:如果异步信号处理程序生成任何信号,则行为未定义。]
POSIX 需要更长的时间,但与 C 库的整体大小相比仍然很短,可以从“异步信号处理程序”安全调用的函数列表,并且还更详细地定义了信号可能“发生其他情况的情况”而不是调用 abort 或 raise 函数的结果。” 如果您正在对信号做任何重要的事情,那么您可能正在编写旨在在具有 Unix 性质的操作系统上运行的代码(而不是 Windows、MVS 或可能没有完整的 C 托管实现的嵌入式实现)首先),您应该熟悉它们的 POSIX 要求以及 ISO C 要求。
| 归档时间: |
|
| 查看次数: |
56686 次 |
| 最近记录: |