C标准库中的函数是否线程安全?

17
我应该在哪里得到一个明确的答案,关于我的memcpy(使用Ubuntu附带的eglibc实现)是否线程安全?老实说,我在文档中没有找到清晰的YES或NO。
顺便说一下,“线程安全”指的是当可以并发地按字节安全复制日期时,可以安全地使用memcpy。如果将只读数据复制到不重叠的区域,则至少应该是可能的。
理想情况下,我想看到类似于ARM编译器文档页面底部的列表。

1
我相信任何类型的memcpy()都是线程安全的,因为我无法想象除了自动/堆栈变量之外还需要使用其他东西。 - trojanfoe
请查看以下链接:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0492c/Chddjdaj.htmlhttp://bytes.com/topic/c/answers/811064-malloc-function-provided-stdlib-h-thread-safe - user2742371
@trojanfoe,如果两个线程复制到一个单一的堆缓冲区,会怎样?每个字节可能来自其中一个副本,但是整个复制过程可能会导致交错。这似乎对我来说像是竞态条件。 - Adam
4
是的,那肯定会造成问题,但这超出了memcpy()是否支持线程安全的范围。调用者需要理解这样做的后果,并提供必要的独占访问权限来保护缓冲区。 - trojanfoe
1
@trojanfoe - 什么?你做过许多(或任何)多线程应用程序吗? - Martin James
3个回答

15
您可以在这里找到该列表,位于第2.9.1 Thread-Safety章节:http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_01 也就是说,这是一个不需要遵守线程安全性的函数列表。所有其他函数都需要遵守线程安全性。 Posix包括标准C库和典型的“unix”接口。 (完整列表在此处,http://pubs.opengroup.org/onlinepubs/9699919799/functions/contents.html
memcpy()由posix指定,但不是2.9.1列表的一部分,因此可以认为是线程安全的。
The various environments on Linux try their best to implement POSIX. The functions on Linux/Glibc may be thread-safe, even if POSIX doesn't require it, although this is rarely documented. For functions/libraries not covered by POSIX, you must rely on the documentation provided by their authors.
As far as I can tell, POSIX considers thread safety to be equivalent to reentrancy and guarantees that there are no internal data races. However, you are responsible for possible external data races, such as protecting yourself from calling functions like memcpy() with memory that might be updated concurrently.

没错。你可能是指的http://pubs.opengroup.org/onlinepubs/9699919799/functions/contents.html中的第2.9.1章节。 - not-a-user

5

这取决于函数及其使用方式。

memcpy为例,通常情况下它是线程安全的,如果你复制的数据源和目标都是某个单独线程内私有的。如果你写入数据并且其他线程可以读取或者写入该数据,那么它就不再是线程安全的,你需要保护访问。


你说得对,我正在寻找有关如何使用哪个函数来实现线程安全的文档。我知道memcpy的作用以及从那个角度来看它应该是线程安全的,但我不知道它是如何实现的。而对于其他函数来说,情况更加复杂。如果一个函数的规范似乎允许实现线程安全,这仍然取决于实际的代码。我可以轻松地编写一个工作正常但不是线程安全的memcpy - not-a-user
2
@temple 不保存任何调用状态的函数是线程安全的。例如,为什么 memcpy 会在调用之间保存任何状态呢?根本没有理由。随机数生成、某些字符串函数需要在调用之间保存状态,这就是为什么你有两个变量的函数(在名称后面添加了 _r)是可重入的原因。 - Some programmer dude
1
好的,我仍然不是在寻找可信度,而是在寻找规范或文档。 - not-a-user

2
如果一个glibc函数不是线程安全的,那么手册会说明,并且通常也会有一个线程安全的变体被记录在文档中。
例如,请参见man strtok

SYNOPSIS #include

   char *strtok(char *str, const char *delim);

   char *strtok_r(char *str, const char *delim, char **saveptr);
< p > _r(代表“可重入”)是线程安全变体。 < p >不幸的是,手册没有习惯性地说明函数是否线程安全,而仅在存在问题时提到线程安全。 < p >与所有函数一样,如果您向其提供指向共享资源的指针,则它将变得不安全。这取决于您如何处理锁定。

_r 函数是 GNU 特定的,因此不具备可移植性 :sadface:(如果这对你很重要的话) - Sam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接