我有一个非常具体的应用程序,我需要一个带持久存储的自动增量变量.
确切地说,我将int变量的十进制表示存储在文件中.要生成下一个数字,我read()从文件中将内容转换回来int,添加1并write()返回到文件.我不需要并发访问这些数据.一个进程中只有一个线程调用函数来检索自动增量编号.该程序在嵌入式环境中运行,没有人可以访问控制台,因此不应该担心安全问题.如果重要,它将在MIPS上的Linux 2.6.24上运行.
问题是,我没有获得100%可重复的结果.有时我会重复数字,这对我的申请来说是不可接受的.
我的实现如下.
在启动应用程序时,我有:
int fd = open("myfile", O_RDWR|O_CREAT|O_SYNC, S_IRWXU|S_IRWXG|S_IRWXO);
Run Code Online (Sandbox Code Playgroud)
并且自动增量功能:
int get_current(int fd)
{
char value[SIZE];
lseek(fd, 0, SEEK_SET);
read(fd, value, SIZE);
return atoi(value);
}
int get_next(int fd)
{
char value[SIZE];
int cur = get_current(fd);
memset(value, 0, SIZE);
sprintf(value, "%d", cur + 1);
lseek(fd, 0, SEEK_SET);
write(fd, value, SIZE);
//fsync(fd); /* Could inserting this be the solution? */
return (cur + 1);
}
Run Code Online (Sandbox Code Playgroud)
为了代码可读性,我故意遗漏了上面的错误检查.我有代码来检查所有系统调用的返回值.
代码最初由另一个人编写,现在我已经检测到了这个问题,解决它的第一步是找出可能导致它的原因.我担心它可能与缓存文件访问的方式有关.我知道当我write()没有保证数据实际到达物理介质时,但是在read()没有呼叫fsync()且仍能得到可预测结果的情况下呼叫是否安全?如果是,那么我就没有想法;)
感谢您的阅读.
是的,写完后立即阅读是安全的.在类Unix系统中,数据在write()返回时安全地存在于内核缓冲池中,并将返回到需要读取数据的其他进程.使用O_SYNC,O_DSYNC,O_FSYNC(确保将数据写入磁盘)和Windows系统时,类似的注释也适用.显然,当aio_write()调用返回时,异步写入将不会完成,但在完成信号通知时它将完成.
但是,您的问题出现是因为您没有确保一次只有一个进程或线程访问该文件.您必须确保获得串行访问权限,以便不会同时从文件中读取两个进程(或线程).这是DBMS术语中的"丢失更新"问题.
您需要确保一次只能访问一个进程.如果您的流程合作,您可以使用建议锁定(通过fcntl()POSIX系统).如果您的流程不合作,或者您不确定,则可能需要强制锁定,或者完全使用其他技术.