记录锁
来源:互联网 发布:三拼动物域名 编辑:程序博客网 时间:2024/06/05 18:24
一、记录锁record locking
若两个人同时编辑一个文件,会出现什么样的后果呢?对于很多UNIX系统,该文件的最后状态取决于写该文件的最后一个进程。但是,对于某些应用程序(例如数据库),进程有时需要确保它正在单独写一个文件。记录锁就是提供这种功能的机制。
记录锁的功能是:当一个进程正在读或者修改文件的某个部分时,它可以阻止其他进程修改同一文件区。
二、fcntl记录锁
#include <fcntl.h>
int fcntl(int filedes,int cmd,.../*struct flock *flockptr*/);
返回值:若成功则依赖于cmd,失败则返回-1
参数:
filedes:文件描述符
cmd:F_GETLK,F_SETLK或F_SETLKW
F_GETLK:获取记录锁状态;F_SETLKW:设置记录锁;F_SETLK:F_GETLK的阻塞版本
flockptr:指向struct flock 的指针
struct flock {
short l_type; /* F_RDLCK, F_WRLCK, or F_UNLCK */
off_t l_start; /* offset in bytes, relative to l_whence */
short l_whence; /* SEEK_SET, SEEK_CUR, or SEEK_END */
off_t l_len; /* length, in bytes; 0 means lock to EOF */
pid_t l_pid; /* returned with F_GETLK */
};
示例1:加锁和解锁一个文件区域
#include "apue.h"
#include <fcntl.h>
int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
{
struct flock lock;
lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */
lock.l_start = offset; /* byte offset, relative to l_whence */
lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
lock.l_len = len; /* #bytes (0 means to EOF) */
return(fcntl(fd, cmd, &lock));
}
因为大多数锁调用是加锁或解锁一个文件区域,故常用以下几个宏:
#define read_lock(fd, offset, whence, len) /
lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))
#define readw_lock(fd, offset, whence, len) /
lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))
#define write_lock(fd, offset, whence, len) /
lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))
#define writew_lock(fd, offset, whence, len) /
lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))
#define un_lock(fd, offset, whence, len) /
lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))
示例2:测试一把锁
#include "apue.h"
#include <fcntl.h>
pid_t lock_test(int fd, int type, off_t offset, int whence, off_t len)
{
struct flock lock;
lock.l_type = type; /* F_RDLCK or F_WRLCK */
lock.l_start = offset; /* byte offset, relative to l_whence */
lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
lock.l_len = len; /* #bytes (0 means to EOF) */
if (fcntl(fd, F_GETLK, &lock) < 0)
err_sys("fcntl error");
if (lock.l_type == F_UNLCK)
return(0); /* false, region isn't locked by another proc */
return(lock.l_pid); /* true, return pid of lock owner */
}
对应的宏为:
#define is_read_lockable(fd, offset, whence, len) / (lock_test((fd), F_RDLCK, (offset), (whence), (len)) == 0)#define is_write_lockable(fd, offset, whence, len) / (lock_test((fd), F_WRLCK, (offset), (whence), (len)) == 0)
示例3:死锁
死锁:如果两个进程互相等待对方持有并且锁定的资源,则这两个进程就处于死锁状态。
#include "apue.h"#include <fcntl.h>static void lockabyte(const char *name, int fd, off_t offset){ if (writew_lock(fd, offset, SEEK_SET, 1) < 0) err_sys("%s: writew_lock error", name); printf("%s: got the lock, byte %ld/n", name, offset);}int main(void){ int fd; pid_t pid; /* * Create a file and write two bytes to it. */ if ((fd = create("templock", FILE_MODE)) < 0) err_sys("creat error"); if (write(fd, "ab", 2) != 2) err_sys("write error"); TELL_WAIT(); if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { /* child */ lockabyte("child", fd, 0); TELL_PARENT(getppid()); WAIT_PARENT(); lockabyte("child", fd, 1); } else { /* parent */ lockabyte("parent", fd, 1); TELL_CHILD(pid); WAIT_CHILD(); lockabyte("parent", fd, 0); } exit(0);}
示例4:在文件整体上加锁
#include <unistd.h>#include <fcntl.h>int lockfile(int fd){ struct flock fl; fl.l_type = F_WRLCK; fl.l_start = 0; fl.l_whence = SEEK_SET; fl.l_len = 0; return(fcntl(fd, F_SETLK, &fl));}
#define lockfile(fd) write_lock((fd), 0, SEEK_SET, 0)三、锁的隐含继承和释放
1 锁与进程和文件两方面有关。
当一个进程终止时,它所建立的锁全部释放。任何时候关闭一个文件描述符时,则该进程通过这一描述符可以引用的文件上
的任何一把锁都被释放。
2 由fork产生的子进程不继承父进程所设置的锁。
3 在执行exec后,新程序可以继承原程序的锁。
四、在文件尾端加锁
在接近文件尾端加锁或解锁要特别小心,否则可能会得不到预期的结果。
五、建议性锁和强制性锁
建议锁要求所有程序自觉遵守协议,先申请资源再使用资源,对不遵守协议的程序没有强制力。
一般unix系统上使用的上建议性锁,只是在合作进程之间才能有效发挥作用,但是对于其他的进程,则没有约束力. 所以定义了强制锁.示例:确定是否支持强制性锁#include <errno.h>#include <fcntl.h>#include <sys/wait.h>#include <sys/stat.h>#include <unistd.h>#include <stdio.h>
void set_fl(int fd,int flags);int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len);
void set_fl(int fd,int flags){ int val;
if((val=fcntl(fd,F_GETFL,0))<0) printf("fcntl F_GETFL error/n"); val|=flags; if((val=fcntl(fd,F_SETFL,0))<0) printf("fcntl F_SETFL error/n");}
int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len){ struct flock lock;
lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */ lock.l_start = offset; /* byte offset, relative to l_whence */ lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */ lock.l_len = len; /* #bytes (0 means to EOF) */
return(fcntl(fd, cmd, &lock));}
#define read_lock(fd, offset, whence, len) / lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))#define readw_lock(fd, offset, whence, len) / lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))#define write_lock(fd, offset, whence, len) / lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))#define writew_lock(fd, offset, whence, len) / lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))#define un_lock(fd, offset, whence, len) / lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))
int main(int argc, char *argv[]){ int fd; pid_t pid; char buf[5]; struct stat statbuf; if (argc != 2) { fprintf(stderr, "usage: %s filename/n", argv[0]); exit(1); }
if ((fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC)) < 0) printf("open error/n"); if (write(fd, "abcdef", 6) != 6) printf("write error");
/* turn on set-group-ID and turn off group-execute */ if (fstat(fd, &statbuf) < 0) printf("fstat error"); if (fchmod(fd, (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0) printf("fchmod error");
// TELL_WAIT();
if ((pid = fork()) < 0) { printf("fork error"); } else if (pid > 0) { /* parent */ /* write lock entire file */ if (write_lock(fd, 0, SEEK_SET, 0) < 0) printf("write_lock error");
// TELL_CHILD(pid);
if (waitpid(pid, NULL, 0) < 0) printf("waitpid error"); } else { /* child */ sleep(5);//WAIT_PARENT(); /* wait for parent to set lock */
set_fl(fd, O_NONBLOCK);
/* first let's see what error we get if region is locked */ if (read_lock(fd, 0, SEEK_SET, 0) != -1) /* no wait */ printf("child: read_lock succeeded"); printf("read_lock of already-locked region returns %d/n",errno);
/* now try to read the mandatory locked file */ if (lseek(fd, 0, SEEK_SET) == -1) printf("lseek error"); if (read(fd, buf, 2) < 0) printf("read failed (mandatory locking works)"); else printf("read OK (no mandatory locking), buf = %2.2s/n", buf); } exit(0);}
[root@localhost chapter_14]# ./14_6 yuanread_lock of already-locked region returns 11read OK (no mandatory locking), buf = ab
- 记录锁
- 记录锁
- 记录锁
- 记录锁
- 记录锁
- 记录锁
- 记录锁
- 记录锁
- 文件锁 记录锁
- 文件锁 记录锁
- 文件锁 记录锁
- 文件锁 记录锁
- oracle 查询 锁记录
- 记录锁详解
- 学习记录锁
- 记录锁 详解
- APUE_记录锁
- Android 锁屏记录
- 关于换行符号,在SMS程序中进行解析时,在linux系统 windows系统的不同
- 查找JAR包的网站
- 网页时钟显示^_^
- vc控制台程序连接oracle关键问题
- 李开复 升级为我的偶像
- 记录锁
- 成本与创新的博弈
- 让别人说话
- 从MSN中断五国服务谈国家安全
- Tomcat6 + MySQL连接池配置
- JAVA HTTP 无组件 上传文件
- javascript 简繁体字转换脚本
- JavaScript效率调优经验
- onblur 事件会在对象失去焦点时发生。