(笔记从chinaunix copy过来的,然后自己看书的时候把认为需要注意的地方添加上,方便复习)
1记录锁的功能
当一个进程正在读或修改文件的某个部分时,它可以阻止其他进程修改同一文件区。我们不应该从字面上去理解记录锁,实际上它应该叫“区域锁”,因为它锁定的只是文件的一部分(也可能是整个文件)(实现了多进程可以同时写文件的不同部分)。这个区域用来存放多用户的共享区。
注意:记录锁在内核中维护,其属主是由属主的进程ID进行标识的,意味着这些锁用于不同进程间的上锁,而不是用于同一进程内不同线程间的上锁。。
2.记录锁的分类
记录锁分为共享读锁和独占写锁,前者也叫做共享锁后者也叫做排他锁。
Posix记录上锁称为劝告性上锁(为什么劝告性锁对协作进程来说就够用了???),其含义是内核维护着已由各个进程上锁的所有文件的信息,但是它不能防止一个进程写已由另一个进程读锁定的某个文件,同样,也不能防止一个进程读已由另一个进程写锁定的某个文件(前提进程有足够读写权限),同步安全性更依赖于程序员控制(即假定程序员会遵守某些规则)
3.加锁规则
如果一个进程对共享区加了共享读锁,其他进程只能加共享读锁。如果一个进程加了独占写锁,其他进程就不能加任何锁。
注意:当前读锁,那么一个等待着的写入者与等待着的读出者优先级比较。一般系统都采用FIFO规则处理,也就有可能一直来读,写入者处于一直等待。不过估计会采用一些规则判断等待时间,等待时间长了就会运行。
4.死锁
如果两个相互等待对方持有并且不释放(已被锁定)的资源是时,则这两个进程就处于死锁状态。如果一个进程已经控制了文件的一个加锁区域,然后它又试图对另一个进程控制的区域加锁,则它就会睡眠,在这种情况下,有发生死锁的可能性
5.锁的隐含继承和释放(1)锁与进程和文件两方面有关系,它和前者关系是:当一个进程结束后,他对文件加的锁也就消失了。它和后者的关系是:当进程close文件描述符,切断文件和进程的联系进程所创建的锁也会消失。
(2)由fork产生的子进程不继承父进程所设置的锁。这意味着,若一个进程得到一把锁,然后调用fork,那么对于父进程创建的锁而言,子进程被视为另一个进程,不会拥有该锁。
(3)在执行exec后,新进程可以继承原执行的锁。因为执行exec前后还是一个进程。我们只是改变进程执行的程序,并没有创建新的进程。
6.启动一个守护进程的唯一副本 记录上锁的一个常见用途是确保某个程序(例如守护进程)在任何时刻只有一个副本在运行。其实就是一个文件的写入锁。运行程序时获取一个文件的写入锁,此处可以是一个文件中一个区域~ ,然后当再次运行该程序时,无法获取该区域的写入锁,保证了唯一副本。
7.NFS上锁
NFS网络文件系统,NFS的大多数实现支持fcntl记录上锁。其实就是当检测到文件描述符指向NFS文件系统时,本地lockd就向服务器的lockd发送锁请求。
8.要注意的问题
1.记录锁只是提供竞争进入某段代码区的功能,不会导致对文件操作失败。也就是说,我们对文件进行加锁后,我们还是可以对文件进行操作。
名称 : : | fcntl |
功能 : | 对文加解锁。 |
头文件 : | #include <pthread.h> |
函数原形 : | int fcntl(int filedes,int cmd,…/*struct flock *flockptr */) ; |
参数 : | filedes 文件描述符 cmd 测试锁或加锁 flockptr 指向 flock 结构的指针 |
返回值: | 若成功返回 0 ,若失败返回错误编号。 |
对于记录锁, cmd 是 F_GETLK,F_SETLKW 或 F_SETLKW. 。
F_GETLK 判断由 flockptr 所描述的锁是否会被另外一把锁排斥。如果存在一把锁,他阻止创建由 flockptr 所描述的锁,则把该现存锁的信息写到 flockptr 指向的结构中。如果不存在这种情况除了将 l_type 设置为 F_UNLCK 之外, flockptr 所描述的其他信息都不变。
F_SETLK 和 F_SETLKW 企图建立一把锁。 F_SETLK 和 F_SETLKW 的区别是 F_SETLKW 是 F_SETLK 的阻塞版本。如果存在其他锁,调用的进程就被阻塞直道捕捉到信号。
第三个参数是一个指向 flock 结构的指针:
struct flock{
short l_type; /*F_RDLCK,F_WRLCK,F_UNLCK*/
off_t l_start; /* 加锁的地址 */
shout l_whence; /* 加锁的偏移地址 */
off_t l_len; /* 加锁区域的长度 */
pid_t l_pid; /* 持有锁的进程 ID*/
};
flock 结构说明:
所希望的锁类型: F_RDLCK( 共享读锁 ) 、 F_WRLCK( 独占性写锁 ) 、 F_UNLCK( 解锁一个区域 ) ,这是由 l_type决定的。
要加锁或解锁区域的起始字节偏移量,这是由 l_statt 和 l_whence 两者决定。
区域的字节长度,由 l_len 表示。
具有能阻塞当前进程的锁,其持有的 ID 存放在 l_pid 中。
如若 l_len 为 0 ,则表示锁的区域从其起点(由 l_start 和 l_whence 决定)开始直至最大可能位置为止。也就是不管添写到该文件中多少数据,它都处于的范围。
如果想锁住整个文件,通常的方法是将 l_start 说明为 0 , l_whence 说明为 SEEK_SET , 1_len 说明为 0 。
还要注意的是,对文件加共享读锁时文件应以只读的方式打开,对文件加独占写锁时文件应以只读的方式打开。
1 .
名称 : : | fcntl |
功能 : | 对文加解锁。 |
头文件 : | #include <pthread.h> |
函数原形 : | int fcntl(int filedes,int cmd,…/*struct flock *flockptr */) ; |
参数 : | filedes 文件描述符 cmd 测试锁或加锁 flockptr 指向 flock 结构的指针 |
返回值: | 若成功返回 0 ,若失败返回错误编号。 |
对于记录锁, cmd 是 F_GETLK,F_SETLKW 或 F_SETLKW. 。
F_GETLK 判断由 flockptr 所描述的锁是否会被另外一把锁排斥。如果存在一把锁,他阻止创建由 flockptr 所描述的锁,则把该现存锁的信息写到 flockptr 指向的结构中。如果不存在这种情况除了将 l_type 设置为 F_UNLCK 之外, flockptr 所描述的其他信息都不变。
F_SETLK 和 F_SETLKW 企图建立一把锁。 F_SETLK 和 F_SETLKW 的区别是 F_SETLKW 是 F_SETLK 的阻塞版本。如果存在其他锁,调用的进程就被阻塞直道捕捉到信号。
第三个参数是一个指向 flock 结构的指针:
struct flock{
short l_type; /*F_RDLCK,F_WRLCK,F_UNLCK*/
off_t l_start; /* 加锁的地址 */
shout l_whence; /* 加锁的偏移地址 */
off_t l_len; /* 加锁区域的长度 */
pid_t l_pid; /* 持有锁的进程 ID*/
};
flock 结构说明:
所希望的锁类型: F_RDLCK( 共享读锁 ) 、 F_WRLCK( 独占性写锁 ) 、 F_UNLCK( 解锁一个区域 ) ,这是由 l_type决定的。
要加锁或解锁区域的起始字节偏移量,这是由 l_statt 和 l_whence 两者决定。
区域的字节长度,由 l_len 表示。
具有能阻塞当前进程的锁,其持有的 ID 存放在 l_pid 中。
如若 l_len 为 0 ,则表示锁的区域从其起点(由 l_start 和 l_whence 决定)开始直至最大可能位置为止。也就是不管添写到该文件中多少数据,它都处于的范围。
如果想锁住整个文件,通常的方法是将 l_start 说明为 0 , l_whence 说明为 SEEK_SET , 1_len 说明为 0 。
还要注意的是,对文件加共享读锁时文件应以只读的方式打开,对文件加独占写锁时文件应以只读的方式打开。