user-0 提问: vsprintf是线程安全的吗？

回复:
user: user-1
content: 引用 26 楼 assembly 的回复:[quote=引用 25 楼 zhao4zhong1 的回复:] 谁说不操作全局变量的函数就是线程安全的？！ 我一直是这么认为的，难道不对？ 赵老师，能不能给个反例？谢谢了！[/quote]  倒也不能认为没引用全局变量就线程安全 如果你给两个线程两个指针指向同一个栈上分配的内存对象，不加锁仍然是线程不安全 又或者使用同一个资源，比如文件或者套接字  但是这里的vsprintf，恐怕在两个线程中撞车的可能性不大吧，如果不对同一个内存缓冲区操作的话 我想象不出一个现代的库实现，vsprintf内部还有什么必要共享某种资源，无论内存 还是文件、套接字等等等等 至于说vsprintf内部加锁，大家打个赌，谁找到有这样的实现就赠送个100分啥的，呵呵——不过不是我给哦

user: user-2
content: 引用 24 楼 assembly 的回复:什么论坛啊，竟然不能修改自己的帖子！ 抱歉，我收回楼上的测试；因为发现了一个问题：  xusiwei1236: 你好！你的测试用例有问题，因为两个线程使用了相同的 char buf[1024]，因此而产生的字符混合，不能怪printf。 我修改了你的代码，把 char buf[1024] 分别挪到两个线程各自的函数内部，测试的结果是：没有混合  不妨你也测试一下。 我只是要证明“sprintf内没有加锁‘这一观点，因而使用了两个线程同时操作同一个str。如果两个线程同时用sprintf格式化两个不同的str，不会有任何问题。 如果sprintf内部加了锁，那么多个线程各自操作不同的字符串（刚才打错了）也会发生锁争用，而这种争用是没有必要的。

user: user-2
content: 引用 24 楼 assembly 的回复:什么论坛啊，竟然不能修改自己的帖子！ 抱歉，我收回楼上的测试；因为发现了一个问题：  xusiwei1236: 你好！你的测试用例有问题，因为两个线程使用了相同的 char buf[1024]，因此而产生的字符混合，不能怪printf。 我修改了你的代码，把 char buf[1024] 分别挪到两个线程各自的函数内部，测试的结果是：没有混合  不妨你也测试一下。 我只是要证明“sprintf内没有加锁‘这一观点，因而使用了两个线程同时操作同一个str。如果两个线程同时用sprintf格式化两个不同的str，不会有任何问题。 如果sprintf内部加了锁，那么多个线程对各自操作不同的线程也会发生锁争用，而这种争用是没有必要的。

user: user-0
content: 引用 25 楼 zhao4zhong1 的回复:谁说不操作全局变量的函数就是线程安全的？！ 我一直是这么认为的，难道不对？ 赵老师，能不能给个反例？谢谢了！

user: user-3
content: 谁说不操作全局变量的函数就是线程安全的？！

user: user-0
content: 什么论坛啊，竟然不能修改自己的帖子！ 抱歉，我收回楼上的测试；因为发现了一个问题：  xusiwei1236: 你好！你的测试用例有问题，因为两个线程使用了相同的 char buf[1024]，因此而产生的字符混合，不能怪printf。 我修改了你的代码，把 char buf[1024] 分别挪到两个线程各自的函数内部，测试的结果是：没有混合  不妨你也测试一下。

user: user-0
content: xusiwei1236: 你好！ 我在Windows XP service pack3 + VC6的环境下，跑了你的代码，不过有一点点调整。测试的结果是这样的： 1.用CriticalSection把两个语句都包括进来，测试了几次，字符是干净的，没有发生混合  void thread_fun1(void *args) {     int i;     for(i=0; i<TESTN; i++) {         EnterCriticalSection (&critical_section);         sprintf(buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",                  "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#"                 );         printf("[thread 1] %03d | %s\n", i, buf); // printf 一般是线程安全的         LeaveCriticalSection (&critical_section);     } }   2.只用CriticalSection保护sprintf，结果：字符发生了混合；这说明：即使printf是安全的，但它保护的并不是整个字符串；猜测也许是一段一段保护的，当然只是猜测。  void thread_fun1(void *args) {     int i;     for(i=0; i<TESTN; i++) {         EnterCriticalSection (&critical_section);         sprintf(buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",                  "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#"                 );         LeaveCriticalSection (&critical_section);         printf("[thread 1] %03d | %s\n", i, buf); // printf 一般是线程安全的     } }   3.只用CriticalSection保护printf，结果：字符发生了混合；参考结果2，个人觉得，也许sprintf没保护；也许sprintf保护了，但不是整个字符串。  void thread_fun1(void *args) {     int i;     for(i=0; i<TESTN; i++) {         sprintf(buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",                  "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#",                 "#","#","#","#","#","#","#","#","#","#"                 );         EnterCriticalSection (&critical_section);         printf("[thread 1] %03d | %s\n", i, buf); // printf 一般是线程安全的         LeaveCriticalSection (&critical_section);     } }   4.不使用CriticalSection，当然发生了混合。

user: user-3
content: VC6： C:\Program Files\Microsoft Visual Studio\VC98\CRT\SRC\VSPRINTF.C

user: user-3
content: 引用 11 楼 zhao4zhong1 的回复:为何不去看看vsprintf的源代码？ Windows： 先 http://www.microsoft.com/visualstudio/chs/downloads#d-2010-express 点开Visual C++ 2010 Express下面的语言选‘简体中文’，再点立即安装   在参考C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\vsprintf.c  Linux： 略

user: user-3
content: 为何不去看看vsprintf的源代码？

user: user-2
content: 正常的实现都不会使用全局变量（或static局部变量）， 也就是说，对于不同的str，是线程安全的。 如果有两个线程同时操作同一个str，是不安全的。  #include <stdio.h> #include <pthread.h>  #ifdef WIN32 	#include <windows.h> 	#define msleep(ms) Sleep((ms)) #else 	#include <unistd.h> 	#define msleep(ms) usleep((ms)*1000) #endif  #define TESTN 10 #define DELAY 100  char buf[1024]; pthread_t tid1, tid2;  void *thread_fun1(void *args) { 	int i; 	for(i=0; i<TESTN; i++) { 		sprintf(buf, "%s%s%s%s%s%s%s%s%s%s",  				"#","#","#","#","#","#","#","#","#","#" ); 		printf("[thread 1] %03d | %s\n", i, buf); // printf 一般是线程安全的 	} }  void *thread_fun2(void *args) { 	int i; 	for(i=0; i<TESTN; i++) { 		sprintf(buf, "%s%s%s%s%s%s%s%s%s%s",  					 ".",".",".",".",".",".",".",".",".","." );	 		printf("[THREAD 2] %03d | %s\n", i, buf); // printf 一般是线程安全的 	} }  int main(int argc, char *argv[]) { 	pthread_create(&tid1, NULL, thread_fun1, NULL); 	pthread_create(&tid2, NULL, thread_fun2, NULL); 	 	msleep(100); 	 	return 0; }  MinGW编译，连续运行10次，重定位到spts.txt:  for /L %i in (1,1,10) do @echo test %i...  & @a >> spts.txt  得到spts.txt（同一行内出现两种字符的就是因为sprintf内没有加锁）:  [thread 1] 000 | ########## [thread 1] 001 | ########## [thread 1] 002 | ########## [thread 1] 003 | ########## [thread 1] 004 | ########## [thread 1] 005 | ########## [thread 1] 006 | ########## [thread 1] 007 | ########## [thread 1] 008 | ########## [thread 1] 009 | ########## [THREAD 2] 000 | .......... [THREAD 2] 001 | .......... [THREAD 2] 002 | .......... [THREAD 2] 003 | .......... [THREAD 2] 004 | .......... [THREAD 2] 005 | .......... [THREAD 2] 006 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | ########## [thread 1] 002 | ########## [thread 1] 003 | ########## [thread 1] 004 | ########## [thread 1] 005 | ########## [thread 1] 006 | ########## [thread 1] 007 | ########## [thread 1] 008 | ########## [thread 1] 009 | ########## [THREAD 2] 000 | .......... [THREAD 2] 001 | .......... [THREAD 2] 002 | .......... [THREAD 2] 003 | .......... [THREAD 2] 004 | .......... [THREAD 2] 005 | .......... [THREAD 2] 006 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | ########## [thread 1] 002 | ########## [thread 1] 003 | ########## [thread 1] 004 | ########## [thread 1] 005 | ########## [thread 1] 006 | ########## [thread 1] 007 | ########## [thread 1] 008 | ########## [thread 1] 009 | ########## [THREAD 2] 000 | .......... [THREAD 2] 001 | .......... [THREAD 2] 002 | .......... [THREAD 2] 003 | .......... [THREAD 2] 004 | .......... [THREAD 2] 005 | .......... [THREAD 2] 006 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | ########## [thread 1] 002 | ########## [thread 1] 003 | ...####### [THREAD 2] 000 | ########## [thread 1] 004 | .......... [THREAD 2] 001 | ########## [thread 1] 005 | .......... [THREAD 2] 002 | ########## [thread 1] 006 | .......... [THREAD 2] 003 | ########## [thread 1] 007 | .......... [THREAD 2] 004 | ########## [thread 1] 008 | .......... [THREAD 2] 005 | ########## [thread 1] 009 | .......... [THREAD 2] 006 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | ########## [thread 1] 002 | ########## [thread 1] 003 | ########## [thread 1] 004 | ########## [thread 1] 005 | ########## [thread 1] 006 | ########## [thread 1] 007 | ########## [thread 1] 008 | ########## [thread 1] 009 | ########## [THREAD 2] 000 | .......... [THREAD 2] 001 | .......... [THREAD 2] 002 | .......... [THREAD 2] 003 | .......... [THREAD 2] 004 | .......... [THREAD 2] 005 | .......... [THREAD 2] 006 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | ########## [thread 1] 002 | ########## [thread 1] 003 | ########## [thread 1] 004 | ########## [thread 1] 005 | ########## [thread 1] 006 | ########## [thread 1] 007 | ########## [thread 1] 008 | ########## [thread 1] 009 | ########## [THREAD 2] 000 | .......... [THREAD 2] 001 | .......... [THREAD 2] 002 | .......... [THREAD 2] 003 | .......... [THREAD 2] 004 | .......... [THREAD 2] 005 | .......... [THREAD 2] 006 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | .......... [thread 1] 002 | ########## [THREAD 2] 000 | ########## [thread 1] 003 | .......... [THREAD 2] 001 | ########## [thread 1] 004 | .......... [THREAD 2] 002 | ########## [thread 1] 005 | .......... [THREAD 2] 003 | ########## [thread 1] 006 | .......... [THREAD 2] 004 | ########## [thread 1] 007 | .......... [THREAD 2] 005 | ########## [thread 1] 008 | .......... [THREAD 2] 006 | ########## [thread 1] 009 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | ########## [thread 1] 002 | ########## [thread 1] 003 | ########## [thread 1] 004 | ########## [thread 1] 005 | .......... [THREAD 2] 000 | ########## [thread 1] 006 | .......... [THREAD 2] 001 | ########## [thread 1] 007 | .......... [THREAD 2] 002 | ########## [thread 1] 008 | .......... [THREAD 2] 003 | ########## [thread 1] 009 | .......... [THREAD 2] 004 | .......... [THREAD 2] 005 | .......... [THREAD 2] 006 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [THREAD 2] 000 | ########## [thread 1] 001 | .......... [THREAD 2] 001 | ########## [thread 1] 002 | .......... [THREAD 2] 002 | ########## [thread 1] 003 | .......... [THREAD 2] 003 | ########## [thread 1] 004 | .......... [THREAD 2] 004 | ########## [thread 1] 005 | .......... [THREAD 2] 005 | ########## [thread 1] 006 | .......... [THREAD 2] 006 | ########## [thread 1] 007 | .......... [THREAD 2] 007 | ########## [thread 1] 008 | .......... [THREAD 2] 008 | ########## [thread 1] 009 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | #######... [thread 1] 002 | ########## [THREAD 2] 000 | ########## [thread 1] 003 | .......... [THREAD 2] 001 | ########## [thread 1] 004 | .......... [THREAD 2] 002 | ########## [thread 1] 005 | .......... [THREAD 2] 003 | ########## [thread 1] 006 | .......... [THREAD 2] 004 | ########## [thread 1] 007 | .......... [THREAD 2] 005 | ########## [thread 1] 008 | .......... [THREAD 2] 006 | ########## [thread 1] 009 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | ..........

user: user-4
content: 引用 10 楼 xusiwei1236 的回复:正常的实现都不会使用全局变量（或static局部变量）， 也就是说，对于不同的str，是线程安全的。 如果有两个线程同时操作同一个str，是不安全的。  #include <stdio.h> #include <pthread.h>  #ifdef WIN32 	#include <windows.h> 	#define msleep(ms) Sleep((ms)) #else 	#include <unistd.h> 	#define msleep(ms) usleep((ms)*1000) #endif  #define TESTN 10 #define DELAY 100  char buf[1024]; pthread_t tid1, tid2;  void *thread_fun1(void *args) { 	int i; 	for(i=0; i<TESTN; i++) { 		sprintf(buf, "%s%s%s%s%s%s%s%s%s%s",  				"#","#","#","#","#","#","#","#","#","#" ); 		printf("[thread 1] %03d | %s\n", i, buf); // printf 一般是线程安全的 	} }  void *thread_fun2(void *args) { 	int i; 	for(i=0; i<TESTN; i++) { 		sprintf(buf, "%s%s%s%s%s%s%s%s%s%s",  					 ".",".",".",".",".",".",".",".",".","." );	 		printf("[THREAD 2] %03d | %s\n", i, buf); // printf 一般是线程安全的 	} }  int main(int argc, char *argv[]) { 	pthread_create(&tid1, NULL, thread_fun1, NULL); 	pthread_create(&tid2, NULL, thread_fun2, NULL); 	 	msleep(100); 	 	return 0; }  MinGW编译，连续运行10次，重定位到spts.txt:  for /L %i in (1,1,10) do @echo test %i...  & @a >> spts.txt  得到spts.txt（同一行内出现两种字符的就是因为sprintf内没有加锁）:  [thread 1] 000 | ########## [thread 1] 001 | ########## [thread 1] 002 | ########## [thread 1] 003 | ########## [thread 1] 004 | ########## [thread 1] 005 | ########## [thread 1] 006 | ########## [thread 1] 007 | ########## [thread 1] 008 | ########## [thread 1] 009 | ########## [THREAD 2] 000 | .......... [THREAD 2] 001 | .......... [THREAD 2] 002 | .......... [THREAD 2] 003 | .......... [THREAD 2] 004 | .......... [THREAD 2] 005 | .......... [THREAD 2] 006 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | ########## [thread 1] 002 | ########## [thread 1] 003 | ########## [thread 1] 004 | ########## [thread 1] 005 | ########## [thread 1] 006 | ########## [thread 1] 007 | ########## [thread 1] 008 | ########## [thread 1] 009 | ########## [THREAD 2] 000 | .......... [THREAD 2] 001 | .......... [THREAD 2] 002 | .......... [THREAD 2] 003 | .......... [THREAD 2] 004 | .......... [THREAD 2] 005 | .......... [THREAD 2] 006 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | ########## [thread 1] 002 | ########## [thread 1] 003 | ########## [thread 1] 004 | ########## [thread 1] 005 | ########## [thread 1] 006 | ########## [thread 1] 007 | ########## [thread 1] 008 | ########## [thread 1] 009 | ########## [THREAD 2] 000 | .......... [THREAD 2] 001 | .......... [THREAD 2] 002 | .......... [THREAD 2] 003 | .......... [THREAD 2] 004 | .......... [THREAD 2] 005 | .......... [THREAD 2] 006 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | ########## [thread 1] 002 | ########## [thread 1] 003 | ...####### [THREAD 2] 000 | ########## [thread 1] 004 | .......... [THREAD 2] 001 | ########## [thread 1] 005 | .......... [THREAD 2] 002 | ########## [thread 1] 006 | .......... [THREAD 2] 003 | ########## [thread 1] 007 | .......... [THREAD 2] 004 | ########## [thread 1] 008 | .......... [THREAD 2] 005 | ########## [thread 1] 009 | .......... [THREAD 2] 006 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | ########## [thread 1] 002 | ########## [thread 1] 003 | ########## [thread 1] 004 | ########## [thread 1] 005 | ########## [thread 1] 006 | ########## [thread 1] 007 | ########## [thread 1] 008 | ########## [thread 1] 009 | ########## [THREAD 2] 000 | .......... [THREAD 2] 001 | .......... [THREAD 2] 002 | .......... [THREAD 2] 003 | .......... [THREAD 2] 004 | .......... [THREAD 2] 005 | .......... [THREAD 2] 006 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | ########## [thread 1] 002 | ########## [thread 1] 003 | ########## [thread 1] 004 | ########## [thread 1] 005 | ########## [thread 1] 006 | ########## [thread 1] 007 | ########## [thread 1] 008 | ########## [thread 1] 009 | ########## [THREAD 2] 000 | .......... [THREAD 2] 001 | .......... [THREAD 2] 002 | .......... [THREAD 2] 003 | .......... [THREAD 2] 004 | .......... [THREAD 2] 005 | .......... [THREAD 2] 006 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | .......... [thread 1] 002 | ########## [THREAD 2] 000 | ########## [thread 1] 003 | .......... [THREAD 2] 001 | ########## [thread 1] 004 | .......... [THREAD 2] 002 | ########## [thread 1] 005 | .......... [THREAD 2] 003 | ########## [thread 1] 006 | .......... [THREAD 2] 004 | ########## [thread 1] 007 | .......... [THREAD 2] 005 | ########## [thread 1] 008 | .......... [THREAD 2] 006 | ########## [thread 1] 009 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | ########## [thread 1] 002 | ########## [thread 1] 003 | ########## [thread 1] 004 | ########## [thread 1] 005 | .......... [THREAD 2] 000 | ########## [thread 1] 006 | .......... [THREAD 2] 001 | ########## [thread 1] 007 | .......... [THREAD 2] 002 | ########## [thread 1] 008 | .......... [THREAD 2] 003 | ########## [thread 1] 009 | .......... [THREAD 2] 004 | .......... [THREAD 2] 005 | .......... [THREAD 2] 006 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [THREAD 2] 000 | ########## [thread 1] 001 | .......... [THREAD 2] 001 | ########## [thread 1] 002 | .......... [THREAD 2] 002 | ########## [thread 1] 003 | .......... [THREAD 2] 003 | ########## [thread 1] 004 | .......... [THREAD 2] 004 | ########## [thread 1] 005 | .......... [THREAD 2] 005 | ########## [thread 1] 006 | .......... [THREAD 2] 006 | ########## [thread 1] 007 | .......... [THREAD 2] 007 | ########## [thread 1] 008 | .......... [THREAD 2] 008 | ########## [thread 1] 009 | .......... [THREAD 2] 009 | .......... [thread 1] 000 | ########## [thread 1] 001 | #######... [thread 1] 002 | ########## [THREAD 2] 000 | ########## [thread 1] 003 | .......... [THREAD 2] 001 | ########## [thread 1] 004 | .......... [THREAD 2] 002 | ########## [thread 1] 005 | .......... [THREAD 2] 003 | ########## [thread 1] 006 | .......... [THREAD 2] 004 | ########## [thread 1] 007 | .......... [THREAD 2] 005 | ########## [thread 1] 008 | .......... [THREAD 2] 006 | ########## [thread 1] 009 | .......... [THREAD 2] 007 | .......... [THREAD 2] 008 | .......... [THREAD 2] 009 | ..........   顶分析！

user: user-0
content: mujiok2003的图片启发了我，去找了一下，发现一个问题：你的图片是IAR 5.4版本中所附文档《EWARM_DevelopmentGuide.ENU.pdf》中第290页上的一段文字； 然后我找了IAR 6.5版本中，相同的文档《EWARM_DevelopmentGuide.ENU.pdf》中叙述REENTRANCY的章节，这次是在第390页上，而且，内容也发生了有趣的变化：   而这也意味着，某些代码，在IAR 5.4上没有问题，而用IAR 6.5却有问题。  这些　没有明确规范　而必须依赖编译器和库具体实现　的细节，在　多线程　或者　中断　的应用环境下，有必要仔细考虑，甚至使用自己的实现。

user: user-5
content: 你可以先看看编译器的手册。 至少sprintf可以放心使用。   引用 15 楼 assembly 的回复:VC6是有源码的，但IAR的没看到。更换开发环境和编译器的时候，总是要面对这个问题。  如akirya所言，vsprintf内部使用了errno，而且C的标准库并没有对线程安全做强制的要求，那么不同的编译器的C库，就存在着使用其它全局量的可能，尽管只是可能，但这也是件让人纠结的事情。  我自己在ARM上写了一个多线程调度的核，用IAR编译。这样就要面对这个问题：线程代码如何放心地使用编译器提供的C库，包括string.h math.h stdlib.h。在编译器厂家不提供C库源码的情况下，该如何确认这些C库中的函数“没有使用全局量”？如果使用这些库函数的时候都拿锁来保护，对于一个C开发者来说，这是不可理喻的。  除非，使用自己的代码。但有。。那些经过底层优化的代码，不是那么容易折腾的，所以还是使用编译器自带的要明智些。  现在我决定这样做： 1.相信 string.h math.h 里的函数是不操作全局量的。 2.其它的函数，需要的时候，用自己的代码，包括vsprintf；不用的函数，就不包括。

user: user-5
content: 以前VC的CRT有单线程与多线程版之分，现在只有多线程版了, 线程安全应该可以保证。

user: user-0
content: 这个核是我自己写的，创建线程的函数都是自己的。不怕大家笑话，就贴几句在这里，可以看到，是非常简陋的：  void k_thread_create_context (struct _thread *p, void*(*proc)(void*), void *para) {     ul cpsr;     int i;      cpsr = get_cpsr ();     cpsr &= ~0x80; //enable IRQ, keep sys mode     p->ctx.cpsr = cpsr;      p->ctx.pc = (ul)proc;     for (i=0; i<CTX_REG_NUM; i++) {         p->ctx.r[i] = 0;     }     p->ctx.r[0] = (ul)para;     p->ctx.sp = (ul)(&(p->stack[USR_STACK_SIZE-1]));     p->ctx.lr = 0; }  int pthread_create (pthread_t *t, const pthread_attr_t *ta, void *(*proc)(void *), void *para) {     struct _thread *p;      if (0 == pthread_idle) {         return -1;     }      enter_critical ();      p = pthread_idle;     pthread_idle = pthread_idle->pnext;     *t = (pthread_t)p;     p->pnext = 0;      k_thread_create_context (p, proc, para);     k_thread_appand_ready (p);      exit_critical ();     return 0; }  _beginthread内部是alloc了内存，给每个线程开辟了C库所需全局量的存储区；而相应的，C库的入口代码也需要相应的调整，比如说引用errno，可能就要写成这样：pthis_thread->errno。  如果开发者使用编译器提供的C库，那么C库里的errno可能就是errno，而不是pthis_thread->errno，因为C库的作者不知道开发者会如何创建线程以及线程的数据结构。

user: user-6
content: 引用 15 楼 assembly 的回复:VC6是有源码的，但IAR的没看到。更换开发环境和编译器的时候，总是要面对这个问题。  如akirya所言，vsprintf内部使用了errno，而且C的标准库并没有对线程安全做强制的要求，那么不同的编译器的C库，就存在着使用其它全局量的可能，尽管只是可能，但这也是件让人纠结的事情。  我自己在ARM上写了一个多线程调度的核，用IAR编译。这样就要面对这个问题：线程代码如何放心地使用编译器提供的C库，包括string.h math.h stdlib.h。在编译器厂家不提供C库源码的情况下，该如何确认这些C库中的函数“没有使用全局量”？如果使用这些库函数的时候都拿锁来保护，对于一个C开发者来说，这是不可理喻的。  除非，使用自己的代码。但有。。那些经过底层优化的代码，不是那么容易折腾的，所以还是使用编译器自带的要明智些。  现在我决定这样做： 1.相信 string.h math.h 里的函数是不操作全局量的。 2.其它的函数，需要的时候，用自己的代码，包括vsprintf；不用的函数，就不包括。 看你的编译器提供怎样的创建线程函数，应该有文档说明。 像VC提供的_beginthreadex就为每个线程提供一个errno，就没有线程安全的问题。

user: user-0
content: 竟然编辑不了自己的帖子。补充一下： 1.相信string.h math.h里的某几个函数是不操作全局量的。例如：memcpy strcpy sin cos等

user: user-0
content: VC6是有源码的，但IAR的没看到。更换开发环境和编译器的时候，总是要面对这个问题。  如akirya所言，vsprintf内部使用了errno，而且C的标准库并没有对线程安全做强制的要求，那么不同的编译器的C库，就存在着使用其它全局量的可能，尽管只是可能，但这也是件让人纠结的事情。  我自己在ARM上写了一个多线程调度的核，用IAR编译。这样就要面对这个问题：线程代码如何放心地使用编译器提供的C库，包括string.h math.h stdlib.h。在编译器厂家不提供C库源码的情况下，该如何确认这些C库中的函数“没有使用全局量”？如果使用这些库函数的时候都拿锁来保护，对于一个C开发者来说，这是不可理喻的。  除非，使用自己的代码。但有。。那些经过底层优化的代码，不是那么容易折腾的，所以还是使用编译器自带的要明智些。  现在我决定这样做： 1.相信 string.h math.h 里的函数是不操作全局量的。 2.其它的函数，需要的时候，用自己的代码，包括vsprintf；不用的函数，就不包括。

user: user-7
content: 个人愚见：不认为vsprintf的实现需要全局变量，LZ可以看看代码中有无static变量或者其它全局变量，一般如果实现中使用了static这样的变量或者是全角变量是会在文档中提及的；但显然vsprintf的文档没有说 所以如果传给它的buffer是两个不同的buffer，个人认为vsprintf是线程安全的。