【转】open参数O_DIRECT的学习
free:这里好几个方法我都没测试成功,最后还是用posix_memalign 对齐的方法成功执行了,贴上代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
//O_DIRECT
#define __USE_GNU 1
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h> int main(void)
{
long i;
const long SIZE = *;
int count=;
char *buf;
posix_memalign((void*)&buf,,SIZE*count);
int fd = open("/dev/pcissda",O_RDWR|O_DIRECT);
for(i=;i<count;i++)
write(fd,buf,SIZE);
free(buf);
close(fd);
return ;
}
open有两个原形:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
这三个参数比较容易看出它们的含义,pathname是文件路径,flags打开文件的标志, mode是打开的模式,返回值应该是打开文件的句柄。
flags标志有下面的定义:
O_RDONLY 以只读的方式打开文件
O_WRONLY 以只写的方式打开文件
O_RDWR 以读写的方式打开文件
O_APPEND 以追加的方式打开文件
O_CREAT 创建一个文件
O_EXEC 如果使用了O_CREAT而且文件已经存在,就会发生一个错误
O_NOBLOCK 以非阻塞的方式打开一个文件
O_TRUNC 如果文件已经存在,则删除文件的内容
O_RDONLY、O_WRONLY、O_RDWR三个标志只能使用任意的一个。
扩展阅读: http://blog.csdn.net/yao_guet/article/details/6460900
open的flags参数中,有一个打开标识:O_DIRECT
网上对于该标志的解释如下:
O_DIRECT (Since Linux 2.4.10)
Try to minimize cache effects of the I/O to and from this file. In general this
will degrade performance, but it is useful in special situations, such as when
applications do their own caching. File I/O is done directly to/from user space
buffers. The I/O is synchronous, that is, at the completion of a read(2) or
write(2), data is guaranteed to have been transferred. See NOTES below for
further discussion.
A semantically similar (but deprecated) interface for block devices is described
in raw(8).
翻译:
该标示是为了写文件或者读文件的I/O高度缓存开销的最小化。一般情况下,该标志会降低性能,但是,在特殊情况下,还是有作用的,例如当应用程序使用自己的高速缓存的时候。文件I/O直接接触到用户内存。I/O操作是同步的,也就是说,一旦read(2)或者write(2)完成,数据可以保证传输完毕。见下面的注释关于更多的讨论。
一个语义相似(但是已经弃用)的块设备处理的接口函数是详见raw(8).
CONFORMING TO
SVr4, 4.3BSD, POSIX.1-2001. The O_DIRECTORY, O_NOATIME, and O_NOFOLLOW flags are
Linux-specific, and one may need to define _GNU_SOURCE to obtain their definitions.
The O_CLOEXEC flag is not specified in POSIX.1-2001, but is specified in POSIX.1-2008.
O_DIRECT is not specified in POSIX; one has to define _GNU_SOURCE to get its defini-
tion.
NOTES
O_DIRECT
The O_DIRECT flag may impose alignment restrictions on the length and address of
userspace buffers and the file offset of I/Os. In Linux alignment restrictions vary by
file system and kernel version and might be absent entirely. However there is cur-
rently no file system-independent interface for an application to discover these
restrictions for a given file or file system. Some file systems provide their own
interfaces for doing so, for example the XFS_IOC_DIOINFO operation in xfsctl(3).
Under Linux 2.4, transfer sizes, and the alignment of the user buffer and the file off-
set must all be multiples of the logical block size of the file system. Under Linux
2.6, alignment to 512-byte boundaries suffices.
The O_DIRECT flag was introduced in SGI IRIX, where it has alignment restrictions simi-
lar to those of Linux 2.4. IRIX has also a fcntl(2) call to query appropriate align-
ments, and sizes. FreeBSD 4.x introduced a flag of the same name, but without align-
ment restrictions.
O_DIRECT support was added under Linux in kernel version 2.4.10. Older Linux kernels
simply ignore this flag. Some file systems may not implement the flag and open() will
fail with EINVAL if it is used.
Applications should avoid mixing O_DIRECT and normal I/O to the same file, and espe-
cially to overlapping byte regions in the same file. Even when the file system cor-
rectly handles the coherency issues in this situation, overall I/O throughput is likely
to be slower than using either mode alone. Likewise, applications should avoid mixing
mmap(2) of files with direct I/O to the same files.
The behaviour of O_DIRECT with NFS will differ from local file systems. Older kernels,
or kernels configured in certain ways, may not support this combination. The NFS pro-
tocol does not support passing the flag to the server, so O_DIRECT I/O will only bypass
the page cache on the client; the server may still cache the I/O. The client asks the
server to make the I/O synchronous to preserve the synchronous semantics of O_DIRECT.
Some servers will perform poorly under these circumstances, especially if the I/O size
is small. Some servers may also be configured to lie to clients about the I/O having
reached stable storage; this will avoid the performance penalty at some risk to data
integrity in the event of server power failure. The Linux NFS client places no align-
ment restrictions on O_DIRECT I/O.
In summary, O_DIRECT is a potentially powerful tool that should be used with caution.
It is recommended that applications treat use of O_DIRECT as a performance option which
is disabled by default.
"The thing that has always disturbed me about O_DIRECT is that the whole inter-
face is just stupid, and was probably designed by a deranged monkey on some
serious mind-controlling substances." — Linus
纵使加上open需要所有的头文件,但是,如果使用该标志的话,还需要在引用头文件“fcntl.h”之前,添加:
//O_DIRECT
#define __USE_GNU 1
#include <fcntl.h>
否则,依旧会出现类似下面的错误:
file.c:28: 错误:‘O_DIRECT’未声明(在此函数内第一次使用)
file.c:28: 错误:(即使在一个函数内多次出现,每个未声明的标识符在其
file.c:28: 错误:所在的函数内也只报告一次。)
扩展阅读: http://bbs.chinaunix.net/thread-683493-1-1.html (O_DIRECT未声明错误解决)
写入数据在用户内存中的首地址要为512的整数倍(如果为块大小的整数倍就更没有问题),所以不能使用数组保存数据,而要使用malloc来申请空间。
const int SIZE = 4096*10(每次写入文件数据块大小)
char *p = malloc(SIZE+512); //多申请512空间
char *q = 0;
q = p&(~511);// 使q是512字节对齐的,q空间的地址范围为SIZE。
int fd = open("文件路径", O_RDWR|O_DIRECT);//省略打开失败判断
write(fd, q, SIZE);//写入
扩展阅读: http://blog.csdn.net/hhtang/article/details/6605951
mmap分配的话,首地址就会是4K对齐。
malloc分配的内存,不管多大,开始地址都不固定。
因此,如果使用malloc,那么,就需要内存首地址的对齐。如果使用mmap的话,则不用考虑这些。
在使用write写入文件的时候:
ssize_t write(int fd, const void *buf, size_t count);
参数count也应该是512的整数倍,因此,如果我希望写count个字节的话,那么就需要在write之前,进行如下的操作:
uint32_t wLen = (pos + 511) & ~511U;
write(fd, buffer, wLen);
如果是512倍数大小写入文件的话,文件的内容不一定是512的整数倍,因此,最后一步对于文件的处理就是:
truncate(fullpath, count);
注意:
1、因为文件的长度是按照512对齐的,而文件内容大小不一定是512的整数倍,因此最后需要进行truncate处理
2、因为写入文件是按照512对齐的,所以,追加文件时,内存开始的地址不一定是512的倍数,因此,该方式不适合文档内容的追加,只适合一次性写入文档。
3、使用“O_DIRECT”参数适合一次性写入文件内容比较大的情况,平常情况下,无需使用该标志。
下面我的一个测试用例,数据只是简单地几十个字节,只是为了说明使用方法罢了。如下:
/******************************************************************
* @file file_O_DIRECT.c
* @version v1.0
* @author ymm
* @date 2015/01/29
* @brief open函数O_DIRECT的使用
* @history
* 1、2015/01/29 author ymm 初步完成
******************************************************************/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
//O_DIRECT
#define __USE_GNU 1
#include <fcntl.h>
#include <stdint.h> #include <sys/mman.h>
#include <errno.h> #define READFILE_BUFFER_SIZE 1 * 1024 * 1024
char fullpath[20]="a.txt"; int Deal()
{
int fd = open(fullpath, O_DIRECT|O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
if( fd < 0 ){
printf("Fail to open output protocol file: \'%s\'", fullpath);
return -1;
} uint32_t bufferLen = (READFILE_BUFFER_SIZE) ;
char *buffer = (char *)mmap(0, bufferLen, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if ( MAP_FAILED == buffer )
{
printf("mmap error!errno=%d\n",errno);
return -1;
}
//mmap返回地址一直4k对齐
printf("mmap first address:%p\n",buffer);
uint32_t address=(uint32_t)buffer;
printf("address=%u;address%4096=%u\n",address,address%4096); uint32_t pos = 0, len = 0;
len = snprintf((char *)(buffer + pos), 128, "my name is yangmingmingming\r\n");
pos += len; if( pos ){
buffer[pos] = '\0';
printf("pos=%d,buffer=%s\n",pos,buffer);
uint32_t wLen = (pos + 4095) & ~4095U;
write(fd, buffer, wLen);
truncate(fullpath, pos);
}
if( buffer ){
munmap(buffer, bufferLen);
buffer = NULL;
}
if( fd > 0 ){
close(fd);
}
return 0;
} int main()
{
Deal();
return 0;
}
【转】open参数O_DIRECT的学习的更多相关文章
- c#中可变参数params关键字学习
引用 https://www.cnblogs.com/maowp/p/8134342.html 基础知识 1.概念 params 是C#开发语言中关键字, params主要的用处是在给函数传参数的时候 ...
- Redis总结(五)缓存雪崩和缓存穿透等问题 Web API系列(三)统一异常处理 C#总结(一)AutoResetEvent的使用介绍(用AutoResetEvent实现同步) C#总结(二)事件Event 介绍总结 C#总结(三)DataGridView增加全选列 Web API系列(二)接口安全和参数校验 RabbitMQ学习系列(六): RabbitMQ 高可用集群
Redis总结(五)缓存雪崩和缓存穿透等问题 前面讲过一些redis 缓存的使用和数据持久化.感兴趣的朋友可以看看之前的文章,http://www.cnblogs.com/zhangweizhon ...
- python 类内部装饰器的实现 与 参数解构学习
学习了函数的装饰器的写法,然后想到如果要在类中初始化或获取信息时能用装饰器做过滤和验证应该怎么写呢, 在网上查了下相关信息,感觉这样也是可以的,不知道会不会有什么问题class Ctj(): clas ...
- 笨办法学python3练习代码13-14:argv参数变量的学习
ex13.py argv参数的学习 #argv:参数变量(argument variable),这是一个标准的编程术语,在其他语言中也可可以看到.argument可译为: 参数 #如果参数是用户在执 ...
- C#形参,实参,值传递参数,引用传递参数,输出参数,参数数组的学习
1)形参 形参顾名思义就是形式上的参数,不是实际的参数,它代替实际传入方法的值.在方法体代码中代表了值本身参与运算.形参定义于参数中,它不同于方法体内局部变量,因为是一个变量,在它的作用域内不允许存在 ...
- 卷积神经网络(CNN)张量(图像)的尺寸和参数计算(深度学习)
分享一些公式计算张量(图像)的尺寸,以及卷积神经网络(CNN)中层参数的计算. 以AlexNet网络为例,以下是该网络的参数结构图. AlexNet网络的层结构如下: 1.Input: 图 ...
- ALSA声卡09_从零编写之参数设置_学习笔记
1.参数设置分析 (1)open: soc_pcm_open 依次调用cpu_dai, dma, codec_dai, machine的open或startup函数 只在dma的open函数里添加参数 ...
- python学习笔记 可变参数关键字参数**kw相关学习
在Python中可以定义可变参数,顾名思义,可变参数就是传入参数是可变的.可以是任意个,以一个简单的数学编程为例,计算 sum = a * a + b * b + .....z * z 函数定义可以如 ...
- (转)SpringMVC学习(六)——SpringMVC高级参数绑定与@RequestMapping注解
http://blog.csdn.net/yerenyuan_pku/article/details/72511749 高级参数绑定 现在进入SpringMVC高级参数绑定的学习,本文所有案例代码的编 ...
随机推荐
- 学号:201521123116 《java程序设计》第一周学习总结
#1. 本章学习总结了解了班级的纪律和期末成绩组成.本周重点学习了java语言的特点具有简单性和结构中立.明白了jdk是java开发人员使用的一种工具,以及编写一个java程序的所需步骤,懂得了jdk ...
- 陈敏-第一周Java课程总结
一.本周学习总结 1.感受到JAVA的神奇魅力,以及其跨平台的优势 2.第一次接触感觉还是有很多不懂. 3.了解了JDK 二.书面作业 (一)为什么java程序可以跨平台运行?执行java程序的步骤是 ...
- 201521123036 《Java程序设计》第13周学习总结
本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 书面作业 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu.edu.cn,分 ...
- mysql查询文章的评论数量
作为小白的我,这个问题弄了半天才解决,特此记录下. 两张表:文章表和评论表 文章表(article):id 评论表(comment):id,c_aid 要求:查询出所有文章及评论数量然后降序显示(没有 ...
- mybatis-分页显示数据
分页用到的两个实体类 package com.yangwei.shop.entity; /** * 注意 get,set,remove 方法与一般的实体类的不同*/ public class Syst ...
- Python扩展方法一二事
前言 跟着一个有强迫症的老板干活是一件极其幸福的事情(你懂的).最近碰到一个问题,简单的说就是对一个对象做出部分修改后仍然返回此对象,于是我就写了一个方法,老板看了之后只有一句话:不雅观,改成直接对此 ...
- Linux学习——Shell基础
1 shell概述 Shell 是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用shell来启动,挂起,停止甚至编写一些程序. Shell 还是一 ...
- ubuntu12.04添加程序启动器到Dash Home
ubuntu12.04 dash home中每个图标对应/usr/share/applications当中的一个配置文件(文件名后缀为.desktop).所以要在dash home中添加一个自定义程序 ...
- 均值滤波去除图像噪声的matlab程序
所谓均值滤波实际上就是用均值替代原图像中的各个像素值. 均值滤波的方法是:对待处理的当前像素,选择一个模板,该模板为其近邻的若干像素组成,用模板中的像素的均值来替代原像素. 优点:算法简单,计算速度快 ...
- HSF服务的开发与使用
1.HSF服务的开发 1) 基于Maven创建一个web工程HSFService,如下图,其他的可以自定义. 2)创建好好在src/main目录下创建一个java目录,并将其设置为sources fo ...