原子操作:
1.添写一个文件
考虑一个进程,它要将数据添加到文件尾端。早期的unix系统并不支持open的O_APPEND选项,所以程序被编写成下列形式:
if(lseek(fd,0L,2)>=0)
write(fd,buf,100);
这种方法是先将文件的当前偏移量移到文件结尾,然后在写文件。这在单个进程而言是没有问题的,但是现在的操作系统都是多进程的,就会容易出现问题。多进程的环境下很容易就会出现两个进程同时使用一个文件的情况,而我们不会知道是那个进程先运行,这与操作系统的进程调度算法有关。所一就有了原子操作的概念,可以帮助我们更好的向文件中写。原子操作就是一组动作要么不做要么全做不存在被其他情况打断的情况。
pread和pwrite函数
#include<unistd.h>
ssize_t pread(int filedes,void *buf,size_t nbyte,off_t offset);
返回值:读到的字节数,若已到文件结尾则返回0,若出错则返回-1。
ssize_t pwrite(int filedes,const void *buf,size_t nbyte,off_t offset);
返回值:若成功则返回已写的字节数,若出错则返回-1。
调用pread相当于顺序调用lseek和read,但是又与这种顺序调用有下列重要区别:
调用pread是,无法中断其定位和读操作,是一个原子操作。
不更新文件指针。
调用pwrite相当于调用lseek和write,但也与他们有类似的区别。
dup和dup2函数
下面两个函数可用来复制一个现存的文件描述符:
#include<unistd.h>
int dup(int filedes);
int dup2(int filedes,int filedes2);
两个函数的返回值:若成功则返回新的文件描述符,若出错则返回-1。
由dup返回的新文件描述符一定是当前可用文件描述符的最小值。用dup2则可以用filedes2参数指定新描述符的数值。如果filedes2已经打开,则先将其关闭。如若filedes等于filedes2,则dup2返回filedes2,而不关闭它。返回的文件描述符与filedes指向同一个文件。
sync、fsync和fdatasync函数
#include<unistd.h>
int fsync(int filedes);
int fdatasync(int filedes);
返回值:若成功则返回0,若出错则返回-1。
void sync(void);
sync函数只是将所有修改过的块缓冲区排入写队列,然后返回,它并不等待实际写磁盘结束。
fsync函数只对由文件描述符filedes指定的单一文件起作用,并且等待写磁盘操作结束,然后返回。fsync可用于数据库这样的应用程序,这种应用程序需要确保将修改过的块立即写到磁盘。
fcntl函数
fcntl函数可以改变已打开的文件的性质。
#include<fcntl.h>
int fcntl(int filedes,int cmd,...);
返回值:若成功则依赖于cmd,若出错则返回-1。
fcntl函数有5种功能:
(1)复制一个现有的描述符(cmd=F_DUPFD)。
(2)获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD)。
(3)获得/设置文件状态标志(cmd=F_GETFEL或F_SETFL)。
(4)获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN)。
(5)获得/设置记录锁(cmd=F_GETLK、F_SETLK或F_SETLKW)。