在没有 C11 线程的情况下,C 标准库函数是否线程安全?
Are C standard library functions thread-safe in absence of C11 threads?
我正在 Windows 上编写多线程程序。由于据我所知没有 windows 支持 C11 线程的 C 实现,我最好的选择是使用本机 WinAPI 多线程。但是有一个问题! C11 标准要求 C 库中的一些函数,例如 malloc
或 I/O 函数是线程安全的。但是,即使定义了 __STDC_NO_THREADS__
,它们是否也必须是线程安全的?如果 C 实现中不存在线程设施,那么它们是线程安全的似乎毫无意义,但这确实有帮助,因为我真的不想将所有 I/O 函数包装在互斥锁中。
最明显和可避免的是那些使用并且通常 return 子例程静态数据元素的函数,即使名称上下文是本地的,它当然在堆上。它们很少见,但我会想到 asctime() 和它的一些朋友。 https://linux.die.net/man/3/asctime The man page says obsolete, use strftime(). However, any function that exhibits 'state' probably has a static inside! For instance, strtok(): https://linux.die.net/man/3/strtok 我从不喜欢它,更喜欢使用指针派生的长度手动解析我的字符串而不修改输入。所以要小心。一个优秀的 C 程序员可以编写这些库例程中的大部分,因此可以想象子例程 static(或文件 static global 或 global)用于提供 'state'.
顺便说一句,根据严格的定义,函数应该没有状态,但是子程序可以!在 C++ 中,JAVA 等方法将它们的状态保存在它们的对象或 class 中,对于线程支持,可以在任一级别或两个级别包含互斥锁,或者您可以制作 JAVA 方法 'synchronized'!
如果您针对 Microsoft 多线程运行时库进行编译和link,则像 malloc() 这样的函数将是线程安全的。
这不是语言保证,但由平台保证。
哦,还有 read MSDN carefully。在 C 或 C++ 中使用线程需要使用 _beginthread()
或 _beginthreadex()
,而不是 Win32 CreateThread
还有更多:https://docs.microsoft.com/en-us/cpp/parallel/multithreading-with-c-and-win32?view=vs-2019
不,无论使用何种线程库,都不能保证标准库函数是线程安全的。 C11 7.1.4/4 明确指出:
The functions in the standard library are not guaranteed to be reentrant and may modify objects with static or thread storage duration.
特定的标准库实现或库标准扩展可能会提供线程安全函数,视具体情况而定。
即使在 C11 中,标准中的原子性或线程安全保证也仅对通过标准定义方式创建的信号或线程有意义。如果线程是通过标准未指定的某种方式创建的,则该线程可能执行的任何操作,包括它可能与其他线程的交互,都将超出标准的管辖范围。
用于在可以创建线程或触发异步信号的系统上进行低级编程的高质量实现通常将允许程序以超出标准要求的方式与此类事物进行交互,因为标准基本上会提供没什么。
我正在 Windows 上编写多线程程序。由于据我所知没有 windows 支持 C11 线程的 C 实现,我最好的选择是使用本机 WinAPI 多线程。但是有一个问题! C11 标准要求 C 库中的一些函数,例如 malloc
或 I/O 函数是线程安全的。但是,即使定义了 __STDC_NO_THREADS__
,它们是否也必须是线程安全的?如果 C 实现中不存在线程设施,那么它们是线程安全的似乎毫无意义,但这确实有帮助,因为我真的不想将所有 I/O 函数包装在互斥锁中。
最明显和可避免的是那些使用并且通常 return 子例程静态数据元素的函数,即使名称上下文是本地的,它当然在堆上。它们很少见,但我会想到 asctime() 和它的一些朋友。 https://linux.die.net/man/3/asctime The man page says obsolete, use strftime(). However, any function that exhibits 'state' probably has a static inside! For instance, strtok(): https://linux.die.net/man/3/strtok 我从不喜欢它,更喜欢使用指针派生的长度手动解析我的字符串而不修改输入。所以要小心。一个优秀的 C 程序员可以编写这些库例程中的大部分,因此可以想象子例程 static(或文件 static global 或 global)用于提供 'state'.
顺便说一句,根据严格的定义,函数应该没有状态,但是子程序可以!在 C++ 中,JAVA 等方法将它们的状态保存在它们的对象或 class 中,对于线程支持,可以在任一级别或两个级别包含互斥锁,或者您可以制作 JAVA 方法 'synchronized'!
如果您针对 Microsoft 多线程运行时库进行编译和link,则像 malloc() 这样的函数将是线程安全的。
这不是语言保证,但由平台保证。
哦,还有 read MSDN carefully。在 C 或 C++ 中使用线程需要使用 _beginthread()
或 _beginthreadex()
,而不是 Win32 CreateThread
还有更多:https://docs.microsoft.com/en-us/cpp/parallel/multithreading-with-c-and-win32?view=vs-2019
不,无论使用何种线程库,都不能保证标准库函数是线程安全的。 C11 7.1.4/4 明确指出:
The functions in the standard library are not guaranteed to be reentrant and may modify objects with static or thread storage duration.
特定的标准库实现或库标准扩展可能会提供线程安全函数,视具体情况而定。
即使在 C11 中,标准中的原子性或线程安全保证也仅对通过标准定义方式创建的信号或线程有意义。如果线程是通过标准未指定的某种方式创建的,则该线程可能执行的任何操作,包括它可能与其他线程的交互,都将超出标准的管辖范围。
用于在可以创建线程或触发异步信号的系统上进行低级编程的高质量实现通常将允许程序以超出标准要求的方式与此类事物进行交互,因为标准基本上会提供没什么。