putchar的线程安全
来源:互联网 发布:网络课 编辑:程序博客网 时间:2024/06/05 23:49
前面调用的stdio函数一般都是printf和fgets。这些函数都是一次读入或输出一串数据。他们的操作是满足原子性的。ANSI C中同时还有putchar和getchar这样的函数。在新版本的putchar和getchar都是有加锁操作的,用来保护缓冲区不被破坏。我开始觉得这有点不好理解,以为单个字符原子性是可以保证的,其实不然。假设putchar用如下的伪代码实现:
int putchar(char c, FILE *stream){//获取缓冲区的队尾指针char *tail = gettail(stream);//移动指针tail++;//将字符写入缓冲区*(tail) = c;return 0;}
问题一下就暴露出来了,两个线程都在调用putchar(),缓冲区的信息就会成为互斥资源。比如如下的情形,线程一在tail++执行之前被挂起了,线程二进入运行,它完整的执行了一次putchar。随后线程一又重新开始运行,它并不知道它获得的tail指针已经不是指向缓冲区末端了,它后续的写入操作将会覆盖掉线程二的写入数据。这大概就是传说中的缓冲区破坏了吧!
现在的getchar和putchar都是可以保护缓冲区不被破坏的,但是保护就意味着加锁和效率降低。为了兼顾效率,ANSI C里面还提供了getchar_unlock和putchar_unlock这些不实现缓冲区保护的快速函数。不过使用这些函数的时候就要注意加flockfile和funlockfile自行对输入输出加锁。下面的代码展示了各函数的区别:
/* * putchar.c * * Demonstrate use of stdio file locking to generate an "atomic" * sequence of character writes (using putchar). If run with an * argument of "1", or no argument, the program uses a sequence * of putchar_unlocked calls within flockfile/funlockfile to * ensure that one threads writes cannot be interleaved with * another's. * * With an argument of "0", the program uses putchar, without * file locks, to show that the writes may be interleaved. * * The putchar[_unlocked] loop is punctuated with sleep(1) calls * to ensure that the desired behavior is demonstrated. Without * some delay, even on a multiprocessor the program may often * fail to display the interleaved output in this simplified * case. * * With file locking, you can expect to see the following output: * * thread 1 * thread 2 * thread 3 * * While without file locking, you can expect to see something * much less predictable, but probably resembling this: * * ttthhhiiisss iiisss ttthhhrrreeeaaaddd 123 * */#include <pthread.h>#include "errors.h"/* * This function writes a string (the function's arg) to stdout, * by locking the file stream and using putchar_unlocked to * write each character individually. */void *lock_routine (void *arg){ char *pointer; flockfile (stdout); for (pointer = arg; *pointer != '\0'; pointer++) { putchar_unlocked (*pointer); sleep (1); } funlockfile (stdout); return NULL;}/* * This function writes a string (the function's arg) to stdout, * by using putchar to write each character individually. * Although the internal locking of putchar prevents file stream * corruption, the writes of various threads may be interleaved. */void *unlock_routine (void *arg){ char *pointer; for (pointer = arg; *pointer != '\0'; pointer++) { putchar (*pointer); sleep (1); } return NULL;}int main (int argc, char *argv[]){ pthread_t thread1, thread2, thread3; int flock_flag = 1; void *(*thread_func)(void *); int status; if (argc > 1) flock_flag = atoi (argv[1]); if (flock_flag) thread_func = lock_routine; else thread_func = unlock_routine; status = pthread_create ( &thread1, NULL, thread_func, "this is thread 1\n"); if (status != 0) err_abort (status, "Create thread"); status = pthread_create ( &thread2, NULL, thread_func, "this is thread 2\n"); if (status != 0) err_abort (status, "Create thread"); status = pthread_create ( &thread3, NULL, thread_func, "this is thread 3\n"); if (status != 0) err_abort (status, "Create thread"); pthread_exit (NULL);}当你选择unlock_routine时,它调用的putchar可以保证缓冲区不被破坏,但很可能会出现字符顺序错误的情况。选用lock_routine时,自己加的文件锁不仅保证了缓冲区不被破坏,还可以保证字符出现的顺序。
0 0
- putchar的线程安全
- putchar
- putchar()
- putchar
- putchar
- 线程安全非线程安全的区别
- java的线程安全
- 线程安全的SyncArrayList
- 线程的安全删除
- 创建安全的线程
- 线程安全的队列
- 安全的线程同步
- 安全的线程同步
- 安全的线程同步
- 安全的线程同步
- 安全的线程同步
- 安全的线程同步
- sevlet的线程安全
- Android 网络通信框架Volley简介(Google IO 2013)
- 第十三周 项目5:将str1和str2连接起来,仍存放到str1中
- Android应用性能优化之优化列表头像过度绘制[一]
- [Unity3D]查看与设置游戏帧数FPS
- 从编写C#程序中所得
- putchar的线程安全
- Double 只保留后面2位小数点
- 【Qt学习一】Qt入门之Qt5.3.2+vs2010(中文版)+opencv2.4.9配置与简单测试
- erlang xrl yrl
- hdu 2795 Billboard(线段树)
- grunt常用模块
- 20141125记录
- select取值、选中、回显
- 零基础开发OpenGL ES 2.0学习笔记-Android篇(一)