6
gcc (GCC) 4.7.2
c89

Is it possible for check if a file has already closed?

I have opened a file using fopen() and closed using fclose(fd).

This file gets opened and closed during the running of the program. However, the user can terminate the program by doing a ctrl-c.

When I go to my cleanup routine, I don't know if the file is in a open or closed state. So if I try and do a fclose(fd) twice, it will stack dump.

Some ideas I have been throwing around:

  1. Add a state to the file to be either opened or closed, and then check that state, means more work for such a simple job.
  2. Don't do anything as the OS will cleanup automatially when the program ends.
  3. Is there is the access function, but that will just checks the mode.

Many thanks in advance,

4

5 回答 5

7

AFAIK,glibc 不提供验证FILE*变量的方法。

保持某种状态或只是设置fdNULL工作,但您必须注意不要在关闭文件之后但在重置之前进入清理例程fd。当 Ctrl+C 向程序发送信号 (SIGINT) 时,您可以在关闭文件和重置 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改为使用。

在您的情况下,fcloseall()清理例程中的简单调用会容易得多。

至于你的问题中的第二个选项,关于什么都不做 - 好吧,操作系统会为你的程序清理一切。那么唯一的缺点是,如果有打开的写入流,一些数据可能不会写入磁盘。但也许在 Ctrl+C 的情况下就可以了。

于 2013-07-30T08:16:42.147 回答
4

我觉得你脑子里有点混乱。

fopen与, fclose,f...函数一起使用的文件处理程序是进程范围。即,它们在应用程序中有效(通常)。

打开文件时会发生两件事:成功与否。如果成功,您可能正在独占使用文件或与其他进程共享。如果你失败了,可能另一个进程已经在使用 file. 搜索_fsopen

当进程正常结束或中断(如Ctrl+C)时,操作系统迟早会释放与进程相关的资源。这适用于文件处理程序、内存、...

关于您的问题,无论您的应用程序是否正常结束Ctrl+C,操作系统都会释放未关闭的文件处理程序。

每当您的应用程序启动时,您都需要打开所需的文件处理程序。操作系统不会让它们为您打开。

于 2013-07-30T09:10:15.133 回答
2

我在不同的情况下遇到了类似的问题(没有竞争条件)。因此,此解决方案既涵盖了标题中的问题,也涵盖了 ant 提出的问题。

fclose(fd)被调用时,内部fd->_fileno低级 I/O 文件描述符设置为 -1(或其他无效的 unix 文件描述符)。所以人们可以检查使用fileno(fd)>=0来验证是否fd仍然是一个有效的流(我原来的问题)。

CTRL-C被按下时,进程接收到一个信号SIGINT并执行相应的信号处理程序(例如一个预定义的函数)。永远不要尝试在信号处理程序中做任何涉及程序状态(除了原子可设置变量,例如标志)的事情,因为信号可能在任何情况下到达,所以即使fclose(fd)在 glibc 中执行时也是如此(因此fd->_fileno在执行期间未定义)处理程序)。因此,这里的规范方法是设置一个触发关闭和返回的标志。然后,主应用程序需要经常检查此标志,如果设置了,则清理并退出。

该程序在CTRL-C按下后完成,不会导致系统清理任何 fd。

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>

char interrupted=0;

void exit_handler(int sig){
    interrupted=1;
}

int main(char** argc, int argv)
{
    FILE *fd;

    signal(SIGINT, exit_handler);
    signal(SIGTERM, exit_handler);

    while(1){
        fd=fopen("filepath.file","w");
        char *tst_str="Test String";
        if(fwrite(tst_str,1,11,fd)!=11)
            printf("Writing Error occured\n");

        if (fileno(fd)>=0){
            printf("FD Closed. (1)\n");
            fclose(fd);
        }
        if (fileno(fd)>=0){
            printf("FD Closed. (2)\n");
            fclose(fd);
        }
        if(interrupted)
            exit(0);
    }
    printf("Done.");
}
于 2018-06-03T11:13:00.117 回答
1

可能对你有帮助,只是一些建议:

您可以使用进程 ID 检查进程打开的文件。

  1. pid_t getpid(void);,返回调用进程的进程ID。
  2. 接下来将此 PID 传递给pfiles命令。

第二:

您可以 int fcloseall (void);在程序终止之前调用。

此函数会导致进程的所有打开流关闭,并断开与相应文件的连接。所有缓冲的数据都被写入,任何缓冲的输入都被丢弃。如果所有文件都成功关闭,则 fcloseall 函数返回值 0,如果检测到错误,则返回 EOF。

于 2013-07-30T08:04:03.940 回答
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.

于 2013-07-30T08:15:52.650 回答