pread()函数、pwrite()函数与原子操作的事事儿

本人linux小菜,此贴复制大牛作品,再次特殊说明,向大牛致敬!

在介绍open函数时,我们详细介绍过O_EXCL标志的作用。
它和O_CREAT一起作用时,就会先测试需要创建的文件在不在,不在就会创建
该文件。如果存在,就出错返回。
但这里的测试和出错是一个原子操作。
什么意思呢,就是说测试和创建是一个不可分割的步骤,他们要么都不执行,
要么就都执行。不会发生测试完后,cpu切换到另一个进程的情况。
那如果没有这O_EXCL标志我们会怎么做呢。
我们可能会编写下面这样的程序:
if((fd=open(pathname,O_WRONLY))==-1){
if(ENOENT==errno){
if((fd=crear(pathname,mode))==-1){
perror("creat error");
exit(1);
}else{
perror("open error");
exit(1);
}
}
}


现在如果a进程在执行这段当执行完open时发现没有这个文件(因为没有指定O_CREAT这个标志)
那么open出错返回,errno被设置成ENOENT,在执行creat前,cpu切换到了另一个进程 B 执行,假如这个时候进程
B 创建了这个文件。并写入了部分数据。然后cpu又切换到A进程去执行。然后A接着调用creat函数。
这时候就会清空这个文件的内容(creat调用相当于open(pathname,O_WRONLY | O_CREAT | O_TRUNC,mode))
那么B进程写入的数据就会丢失。
问题就是出在了 对文件存在与否的测试和不存在就创建文件 是两个函数完成的,而任何一个需要两个分开的函数调用
的操作都不可能是原子操作,因为在这两个函数调用之间,内核有可能挂起改进程而去执行别的进程。就像
上面做的那样。



那么如果我们需要再一个文件的某个任意位置出开始(读)写数据。那么我们就需要两个操作一个是定位操作,然后是
(读)写数据操作。
XSI扩展中定义了两个可以原子 定位读写的 函数
ssize_t pread(int fileds, void *buf ,sizt_t nbutes,off_t offset);
ssize_t pwrite(int filedes,void *buf,size_t nbytes,off_t offset);


这里除了他们是原子操作外还有一点需要注意  pread()不更新文件指针
什么意思呢,我们写一段测试代码看看就知道了
我们创建了一个文件test 内容为“123456789”


a程序先先练两次调用read(),每次读取三个字节
b程序先调用pread()在离文件头五个字节出读3数据,然后在调用read()读取三个字节。




a程序为:
 
 9 fd=open("test",O_RDONLY);
 10         read(fd,buf,3);
 11         buf[3]='\0';
 12         printf("%s\n",buf);
 13         read(fd,buf,3);
 14         buf[3]='\0';
 15         printf("%s\n",buf);


输出为:
123
456


b程序为


 9 fd=open("test",O_RDONLY);
 10         pread(fd,buf,3,5);
 11         buf[3]='\0';
 12         printf("%s\n",buf);
 13         read(fd,buf,3);
 14         buf[3]='\0';
 15         printf("%s\n",buf);
输出为:
678
123


从输出我们可以很清楚的看出。pread()调用并不会改变文件指针。上面b程序中pread读取三个数据后
你可能会觉得文件当前偏移量变成8了 后面的read调用会从9开始读。但是pread实际上是不会改变文件指针
所以后面的read会从文件头开始读取。
而read调用会改变文件指针,所以a程序中第二次read调用会从第一次读完的地方接着读。

同理对于pwrite()函数。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值