fcntl

原文链接: http://blog.chinaunix.net/uid/20775448/cid-172636-list-1.html

http://blog.chinaunix.net/uid/20775448/cid-172636-list-1.html

https://blog.csdn.net/zhoulaowu/article/category/1718823/3

Unix系统允许多个进程同时对一个文件进行读写,虽然每一个read或write调用本身是原子的,但内核在两个读写操作之间并没有加以同步,因此当一个进程多次调用read来读文件时,其它进程有可能在两次read之间改变该文件,造成文件数据的随机性冲突。为解决此类并发进程对共享文件的访问控制问题,Unix系统设计了文件锁技术。

1.1 读锁与写锁

Unix系统对文件加锁有两种粒度:文件锁和记录锁,文件锁用来锁定整个文件,而记录锁可以锁定文件的部分区域甚至一个字节,进程通过为文件设置多个记录锁,可以实现文件中不同区域的数据的读写同步,因此记录锁最为常见。记录锁根据访问方式的不同,又分为读锁和写锁。读锁允许多个进程同时进行读操作,也称共享锁。文件加了读锁就不能再设置写锁,但仍允许其他进程在同一区域再设置读锁。写锁的主要目的是隔离文件使所写内容不被其他进程的读写干扰,以保证数据的完整性。写锁一旦加上,只有上锁的人可以操作,其他进程无论读还是写只有等待写锁释放后才能执行,故写锁又称互斥锁,写锁与任何锁都必须互斥使用.

1.2 建议锁和强制锁

Unix文件锁根据实现机制的不同,又可分为建议锁和强制锁两种类型。建议锁由应用层实现,内核只为用户提供程序接口,并不参与锁的控制和协调,也不对读写操作做内部检查和强制保护,其工作原理类似于信号量机制,用户首先定义并初始化特定的锁,再根据进程间的的关系来调用相应的锁操作,只有所有进程都严格遵循锁的使用规则,才能有效防止同步错误,否则,只要有一个例外,整个锁的功能就会被破坏。

 

强制锁则由内核强制实施,每当有进程调用read或write时,内核都要检查读写操作是否与已加的锁冲突,如果冲突,阻塞方式下该进程将被阻塞直到锁被释放,非阻塞方式下系统将立即以错误返回。显然,使用强制锁来控制对已锁文件或文件区域的访问,是更安全可靠的同步形式,适用于网络连接、终端或串并行端口之类须独占使用的设备文件,因为对用户都可读的文件加一把强制读锁,就能使其他人不能再写该文件,从而保证了设备的独占使用。由于强制锁运行在内核空间,处理机从用户空间切换到内核空间,系统开销大,影响性能,所以应用程序很少使用。建议锁开销小,可移植性好,符合POSIX标准的文件锁实现,在数据库系统中应用广泛,特别是当多个进程交叉读写文件的不同部分时,建议锁有更好的并行性和实时性

函数原型定义为:int fcntl(int fd,int cmd,int arg),参数fd表示需要加锁的文件的描述符;参数cmd指定要进行的锁操作,如设置、解除及测试锁等;参数arg是指向锁结构flock的指针。

无论哪种类型的文件锁,使用的流程是确定的:首先以匹配的方式打开文件,然后各进程调用上锁操作同步对已锁区域的读写,读或写完成时再调用解锁操作,最后关闭文件。锁操作代码的编写方法基本类似,首先形成适当的flock结构,然后调用fcntl完成实际的锁操作。为避免每次分配flock并填充各成员的重复工作,可以预先定义专门的函数来完成频繁调用的上锁和解锁操作。下列代码就是为一个文件设置读锁的实例。

获取文件的flags,即open函数的第二个参数:

       flags = fcntl(fd,F_GETFL,0);

2、设置文件的flags:

      fcntl(fd,F_SETFL,flags);

3、增加文件的某个flags,比如文件是阻塞的,想设置成非阻塞:

       flags = fcntl(fd,F_GETFL,0);

       flags |= O_NONBLOCK;

      fcntl(fd,F_SETFL,flags);

O_NONBLOCK和O_NDELAY所产生的结果都是使I/O变成非阻塞模式(non-blocking),在读取不到数据或是写入缓冲区已满会马上return,而不会阻塞等待。

它们的差别在于:在读操作时,如果读不到数据,O_NDELAY会使I/O函数马上返回0,但这又衍生出一个问题,因为读取到文件末尾(EOF)时返回的也是0,这样无法区分是哪种情况。因此,O_NONBLOCK就产生出来,它在读取不到数据时会回传-1,并且设置errno为EAGAIN。

 

你可能感兴趣的:(C)