gcc (GCC) 4.7.2
c89
是否可以检查文件是否已关闭?
我使用fopen()
打开了一个文件,并使用fclose(fd)
关闭了。
在程序运行期间打开和关闭此文件。但是,用户可以通过执行ctrl-c
来终止程序。
当我进入清理程序时,我不知道文件是处于打开还是关闭状态。因此,如果我尝试两次fclose(fd)
,它将堆叠转储。
我一直在撒谎的一些想法:
- 向文件添加要打开或关闭的状态,然后检查该状态,意味着为这么简单的工作做更多的工作。
- 不要做任何事情,因为操作系统会在程序结束时自动清理。
- 是否有访问功能,但这只会检查模式。
醇>
非常感谢,
答案 0 :(得分:6)
AFAIK,glibc没有提供验证FILE*
变量的方法。
保持某种状态或仅将fd
设置为NULL
有效,但是在关闭文件之后但在重置{{1}之前,必须小心不要进入清理例程}。当Ctrl + C向程序发送信号(SIGINT)时,您可以在文件关闭和fd重置时阻止信号。因此,主程序中的fd
应如下所示:
fclose
在你的清理程序中,你应该检查// 1. Block SIGINT
sigset_t old_mask, to_block;
sigemptyset(&to_block);
sigaddset(&to_block, SIGINT);
sigprocmask(SIG_BLOCK, &to_block, &old_mask);
// 2. Close the file and reset fd
fclose(fd);
fd = NULL;
// 3. Restore signal handling
sigprocmask(SIG_SETMASK, &old_mask, NULL);
:
fd
如果您的程序是多线程的,则应使用if (fd != NULL) fclose(fd);
代替。
在您的情况下,在清理例程中简单调用pthread_sigmask
会更容易。
关于你问题中的第二个选项,关于什么都不做 - 好吧,操作系统会为你的程序清理一切。然后唯一的缺点是,如果有打开的写入流,某些数据可能不会写入磁盘。但也许在Ctrl + C的情况下它就可以了。
答案 1 :(得分:4)
我觉得你脑子里有一点混乱。
与fopen
,fclose
,f...
函数一起使用的文件处理程序是进程范围。即,它们在申请中是有效的(通常)。
打开文件时可能会发生两件事:你成功与否。如果成功,您可能只使用文件或与其他进程共享。如果失败,可能另一个进程已经在使用文件。搜索_fsopen
。
当进程结束时,通常或中断(与Ctrl+C
一样),OS迟早会释放与进程相关的资源。这适用于文件处理程序,内存,......
关于您的问题,无论您的应用程序是正常结束还是Ctrl+C
结束,操作系统都会发布未关闭的文件处理程序。
每当您的应用程序启动时,您都需要打开所需的文件处理程序。操作系统不会为您打开它们。
答案 2 :(得分:2)
我在不同的情况下遇到了类似的问题(没有竞争条件)。所以这个解决方案既包括标题中的问题,也包括蚂蚁提出的问题。
调用fclose(fd)
时,内部fd->_fileno
低级I / O文件描述符设置为-1(或其他无效的unix文件描述符)。因此,可以使用fileno(fd)>=0
检查fd
是否仍然是有效的流(我的原始问题)。
当按下CTRL-C
时,该过程接收被称为SIGINT
的信号并执行相应的信号处理程序(例如预定义的函数)。在信号处理程序中,不应该尝试做任何涉及程序状态的任何事情(除了原子可设置变量,例如标志),因为信号可能在任何情况下到达,所以即使在glibc中执行fclose(fd)
(所以{在执行处理程序期间未定义{1}}。因此,这里的规范方法是设置触发关闭和返回的标志。然后主应用程序需要经常检查此标志,如果已设置,则清理并退出。
此程序在按下fd->_fileno
后结束,而不会导致系统清除任何fd。
CTRL-C
答案 3 :(得分:1)
可能对你有所帮助,只是一些建议:
您可以使用进程ID检查进程打开的文件。
pid_t getpid(void);
,返回调用进程的进程ID。pfiles
命令。第二:
您可以在程序终止前致电int fcloseall (void);
。
此函数会导致关闭进程的所有打开流 与要破解的相应文件的连接。所有缓冲数据 写入并丢弃任何缓冲的输入。 fcloseall函数 如果所有文件都成功关闭,则返回值0 如果检测到错误,则为EOF。
答案 4 :(得分:0)
int sig_int(int signo)
{
if(fdOpen)
fclose(fd);
abort();
}
然后将其添加到main
:
static volatile fdOpen = 0;
static FILE *fd;//I guess
if(signal(SIGINT,sig_int) == SIG_ERR)
printf("signal(SIGINT) error\n");
if((fd =fopen("your_file_name","flag_you_need")) != NULL)
fdOpen = 1;
在fcolse之前执行此操作:
sigset_t newmask,oldmask;
sigemptyset(&newmask);
sigaddset(&newmask, SIGINT);
sigprocmask(SIG_BLOCK, &newmask, &oldmask);//BLOCK SIGINT
在正常关闭文件fdOpen = 0 ;
//SIGINT will not interrupt us now.
然后
sigprocmask(SIG_SETMASK,&oldmask,NULL);//RESET signal mask
所以我们做了一些干净的工作,然后在sig_int
退出该计划。