2013-06-25 17 views
1

我正在Linux环境下开发C代码。我使用fwrite将一些数据写入某些文件。该计划将运行在经常发生停电的环境中(至少每天一次)。因此,我希望fwrite可确保在写入数据时发生断电时不应更新文件。它应该只在fwrite完成工作时保存该文件。我如何才能使用fwrite只影响文件完成写入过程?在Linux上使用fwrite作为原子进程

编辑:我使用的fopen与wb丢弃文件在以前的信息和如写一个新的文件

FILE *rtng_p; 
rtng_p = fopen("/etc/routing_table", "wb"); 
fwrite(&user_list, sizeof(struct routing), 40, rtng_p); 

,这是一个非常小的数据一些字节长

回答

5

首先将文件写入到一个临时路径上的同一个文件系统,像/etc/routing_table.tmp。然后,只需重命名原始文件顶部的副本。重命名保证原子。

因此,调用序列将是:fopen,fwritefcloserename

2

另外在David Schwartz answer给出的顺序,你也许可以使用带有例如咨询锁flock(2)系统调用(或者lockf(3)fcntl(2)F_SETLK ....)

这将意味着增加,刚过

FILE * fil = fopen("/etc/routing_table.tmp", "wb"); 

线

if (!fil) 
    { perror("/etc/routing_table.tmp"); exit(EXIT_FAILURE); }; 
if (flock(fileno(fil), LOCK_EX)) 
    { perror("flock LOCK_EX"); exit(EXIT_FAILURE); }; 

,并在结束时,你会

if (fflush(fil)) /* flush the file before unlocking it!!*/ 
    { perror("fflush"); exit(EXIT_FAILURE); }; 
if (flock(fileno(fil), LOCK_UN)) 
    { perror("flock LOCK_UN"); exit(EXIT_FAILURE); }; 
if (fclose (fil)) 
    { perror("fclose"); exit(EXIT_FAILURE); };; 
if (rename("/etc/routing_table.tmp", "/etc/routing_table")) 
    { perror("rename"); exit(EXIT_FAILURE); }; 

使用这样的adv异步锁定将确保即使程序的两个进程正在运行,只有一个会写入该文件。

但它可能是矫枉过正。

顺便说一句,你似乎在/etc/写二进制数据。我认为这是违背习惯或惯例的(见Linux Filesystem HierarchyLinux Standard Base)。我期望/etc下的文件是文本文件。也许你想要你的文件在/var/lib

另请参见Advanced Linux Programming在线预订。

1

在UNIX/Linux社区中,关于open/write/close/rename模式(如David Schwartz's answer中所述)是否实际上保证为原子的问题一直存在争议。注意这个对话是关于write而不是fwrite

的EXT4文件系统的主要作者不认为它应该根据POSIX和文件系统并没有把它当作原子的早期版本得到保证。最终他投降,并将这组操作原子化为EXT4的默认行为。然而,有人声称用户程序实际上应该在做open/write/fsync/close/rename

如果没有fsync,其他文件系统可能无法保证原子性,如果EXT4使用noauto_da_alloc安装,那么该保证也会丢失。所以如果你想要非常安全,你应该在rename之前close之后加fsync。如果您使用fflush,我可能会使用fwrite

请参阅auto_da_alloc章节https://www.kernel.org/doc/Documentation/filesystems/ext4.txt了解更多信息。另请参见EXT4的主要作者撰写的文章:http://thunk.org/tytso/blog/2009/03/12/delayed-allocation-and-the-zero-length-file-problem/

+0

除非发生崩溃,'open/write/close/rename'是_logically_ atomic [因为'rename' is],这是OP [和大多数]是关注于。为了在崩溃时提供原子性,它应该是'open/write/fsync/close/rename/fsync',其中第二个'fsync'用于包含_directory_的文件描述符[否则,它不会立即更新]。否则,在崩溃后,您将更新文件数据,但该目录可能指向旧的inode [dirent的ondisk副本从未更新过]。顺便说一句,如果你在'fsync'之前'关闭',你没有'fsync'的fd –

相关问题