linux线程和fopen()fclose()fgets()
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了linux线程和fopen()fclose()fgets(),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含2919字,纯文字阅读大概需要5分钟。
内容图文
![linux线程和fopen()fclose()fgets()](/upload/InfoBanner/zyjiaocheng/970/f4aa40d15451416b848b96d0913ee76f.jpg)
我正在看一些使用pthreads的遗留Linux代码.
在一个线程中,通过fgets()读取文件. FILE变量是在所有线程之间共享的全局变量. (嘿,我没写这个…)
在另一个线程中,FILE一次又一次地关闭并用另一个文件名重新打开.
发生这种情况几秒钟后,线程fgets()就像继续读取它从上一个文件中读取的最后一条记录一样:几乎就像有错误但fgets()没有返回NULL.然后它自行排序并开始从新文件中读取.
代码看起来有点像这样(为了简洁起见,我希望它仍然可以理解):
在一个线程中:
while(gRunState != S_EXIT){
nanosleep(&timer_delay,0);
flag = fgets(buff, sizeof(buff), gFile);
if (flag != NULL){
// do something with buff...
}
}
在另一个线程中:
fclose(gFile);
gFile = fopen(newFileName,"r");
没有锁定以确保fgets()不会与fclose()/ fopen()同时调用.
有关失败模式的任何想法可能导致fgets()失败但不返回NULL?
解决方法:
所描述的代码如何出错
stdio库缓冲数据,分配内存以存储缓冲的数据. GNU C库动态分配文件结构(某些库,特别是在Solaris上,使用指向静态分配的文件结构的指针,但缓冲区仍然是动态分配的,除非你设置缓冲否则).
如果您的线程使用指向全局文件指针的指针的副本(因为您将文件指针作为参数传递给函数),那么可以想象代码将继续访问已经分配的数据结构(甚至虽然它被关闭释放了,但是会从已经存在的缓冲区中读取数据.只有当您退出函数或读取超出缓冲区内容时才会出现问题 – 或者先前分配给文件结构的空间将重新分配以供新用途使用.
FILE *global_fp;
void somefunc(FILE *fp, ...)
{
...
while (fgets(buffer, sizeof(buffer), fp) != 0)
...
}
void another_function(...)
{
...
/* Pass global file pointer by value */
somefunc(global_fp, ...);
...
}
概念证明代码
使用GCC 4.0.1在MacOS X 10.5.8(Leopard)上测试:
#include <stdio.h>
#include <stdlib.h>
FILE *global_fp;
const char etc_passwd[] = "/etc/passwd";
static void error(const char *fmt, const char *str)
{
fprintf(stderr, fmt, str);
exit(1);
}
static void abuse(FILE *fp, const char *filename)
{
char buffer1[1024];
char buffer2[1024];
if (fgets(buffer1, sizeof(buffer1), fp) == 0)
error("Failed to read buffer1 from %s\n", filename);
printf("buffer1: %s", buffer1);
/* Dangerous!!! */
fclose(global_fp);
if ((global_fp = fopen(etc_passwd, "r")) == 0)
error("Failed to open file %s\n", etc_passwd);
if (fgets(buffer2, sizeof(buffer2), fp) == 0)
error("Failed to read buffer2 from %s\n", filename);
printf("buffer2: %s", buffer2);
}
int main(int argc, char **argv)
{
if (argc != 2)
error("Usage: %s file\n", argv[0]);
if ((global_fp = fopen(argv[1], "r")) == 0)
error("Failed to open file %s\n", argv[1]);
abuse(global_fp, argv[1]);
return(0);
}
在自己的源代码上运行时,输出为:
Osiris JL: ./xx xx.c
buffer1: #include <stdio.h>
buffer2: ##
Osiris JL:
因此,经验证明在某些系统上,我概述的情景可能会发生.
如何修复代码
在其他答案中很好地讨论了对代码的修复.如果你避免我说明的问题(例如,通过避免全局文件指针),这是最简单的.假设这是不可能的,使用适当的标志进行编译可能就足够了(在许多类Unix系统上,编译器标志’-D_REENTRANT’完成工作),最终你将使用基本标准的线程安全版本I / O功能.如果做不到这一点,您可能需要围绕对文件指针的访问放置明确的线程安全管理策略;一个互斥体或类似的东西(并修改代码以确保线程在使用相应的文件指针之前使用互斥锁).
内容总结
以上是互联网集市为您收集整理的linux线程和fopen()fclose()fgets()全部内容,希望文章能够帮你解决linux线程和fopen()fclose()fgets()所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。