概述
读写锁
当一个进程正在读或者修改某个文件的某个部分时,组织其他进程修改同一个文件或者同一个文件的某个区域。对于Linux来说一切皆是文件,包括IO设备共享内存;
接口
int fcntl(int fd, int cmd, struct flock *lock);表示锁操作;fd:表示文件描述符;cmd:表示命令,F_GETLK:表示获取锁;设置锁:F_SETLK,用于加解锁;F_SETLKW用于设置加解阻塞锁;
struct flock {
i_type //F_RDLCK:表示读取锁,读取锁是共享锁;F_WRLCK:是写入锁,写入锁是排它锁;F_UNLCK:表示用于解锁;
I_whence //SEEK_SET:表示在文件的开头为锁定的起始位置;SEEK_CUR:表示以目前读写位置为锁定的起始位置;SEEK_END:表示以文件的结尾为锁定的起始位置;
I_start //表示相对于I_whence位置的偏移量;
I_len //表示锁定区域的长度,0表示全文;
I_pid //当前占用锁的的PID,只对F_GETLK命令有效;
};
返回值:-1表示失败,0表示SET命令设置成功;
记录锁:获取锁信息fcntl(fd,F_GETLK);设置锁:fcntl(fd,F_SETLK,arg);fcntl(fd,F_SETLKW,arg);
file_wrlock.c
#include
#include
#include
#include
#include
int fd;
void handler(int sig){
struct flock lock;
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if(-1 == fcntl(fd,F_SETLKW,&lock)){
perror("fcntl error");
exit(1);
}
}
int main(int argc, char* argv[]){
signal(SIGUSR1,handler);
int c,start = 0,len = 0;
while((c = getopt(argc,argv,"s:l:"))!=-1){
switch(c){
case 's':
start = atoi(optarg);
break;
case 'l':
len = atoi(optarg);
break;
}
}
if(optind != argc -1){
printf("usage:%s [-s ] [-l ] n",argv[0]);
return 1;
}
fd = open(argv[optind],O_WRONLY);
if(-1 == fd){
perror("open error");
return 1;
}
struct flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = start;
lock.l_len = len;
if(-1 == fcntl(fd,F_SETLKW,&lock)){
perror("fcntl error");
return 1;
}
pause();
for(;;);
close(fd);
}
文件读锁:
file_rdlock.c
#include
#include
int main(int argc, char* argv[]){
if(2!=argc){
printf("usage:%s n",argv[0]);
return 1;
}
int fd = open(argv[1],O_RDONLY);
if(-1 == fd){
perror("open error");
return 1;
}
struct flock lock;
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if(-1 == fcntl(fd,F_SETLK,&lock)){
perror("fcntl error");
return 1;
}
pause();
close(fd);
}
view_lock.c:用于查看锁的状态,但是一般只能用于查看写锁的状态,不能够查看读锁的状态;
#include
#include
#include
int main(int argc, char* argv[]){
if(2!=argc){
printf("usage:%s n",argv[0]);
return 1;
}
int fd = open(argv[1],O_RDWR);
if(-1 == fd){
perror("open error");
return 1;
}
struct flock lock;
bzero(&lock,sizeof(lock));
if(-1 == fcntl(fd,F_GETLK,&lock)){
perror("fcntl error");
return 1;
}
printf("file:%s,lock type:%d,start:%d,len:%d,by %dn",argv[1],lock.l_type,lock.l_start,lock.l_len,lock.l_pid);
}
file_unlock.c:用于解除锁,解锁操作只能在本进程完成,否则解锁操作就会失败;
#include
#include
int main(int argc, char* argv[]){
if(2!=argc){
printf("usage:%s n",argv[0]);
return 1;
}
int fd = open(argv[1],O_WRONLY);
if(-1 == fd){
perror("open error");
return 1;
}
struct flock lock;
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if(-1 == fcntl(fd,F_SETLKW,&lock)){
perror("fcntl error");
return 1;
}
pause();
close(fd);
}
读写锁的分类
访问操作:同一个进程访问只会覆盖已有的锁;锁包含写入锁(排它锁);读写锁(共享锁);加锁区域:文件锁,对于整个文件上锁;记录锁:对于文件的部分区域上锁;
锁的实现方式:
建议性锁(Advisory locking)别名, 劝诫锁,协作锁,每个上锁的进程都需要检查是否有锁存在,当然还需要尊重已有的锁,这个规范需要程序员来实现;
强制性锁(Mandatory locking):当文件悲伤所来进行写入操作时,在锁定该文件的进程释放锁之前,内核会阻止任何对该文件的读或者写的访问(open、read、write),每次读或者写访问之前,都得检查锁是否存在,但是缺点是内核实现,系统开销很大,并且系统之间的兼容性很差(Mac OS不支持强制性锁);本质是内核读写文件自动处理;
设置:mount -o remount,mand/nomand分别表示允许强制锁定,禁止强制锁定;写该文件权限:chmod g+s,g-x来设置权限;
进程死锁的情况:
deadlock.c
#include
#include
#include
#include
void lock(const char* pathname){
int fd = open(pathname,O_WRONLY);
if(-1 == fd){
perror("open error");
exit(1);
}
struct flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if(-1 == fcntl(fd,F_SETLKW,&lock)){
perror("fcntl error");
exit(1);
}
//close(fd);
}
int main(int argc, char* argv[]){
if(3!=argc){
printf("usage:%s n",argv[0]);
return 1;
}
printf("PID:%d lock file %sn",getpid(),argv[1]);
lock(argv[1]);
printf("sleep 1sn");
sleep(1);
printf("PID:%d lock file %sn",getpid(),argv[2]);
lock(argv[2]);
pause();
}
补充一个关于lseek函数
lseek_append.c:用于实现在文件的特定位置插入数据,但是不进行覆盖操作;
#include
#include
#include
#include
#include
int main(int argc,char* argv[]){
if(4 != argc){
printf("usage:%s n",argv[0]);
return 1;
}
int fd = open(argv[1],O_RDWR);
if(-1 == fd){
return 1;
}
off_t off = lseek(fd,atoi(argv[2]),SEEK_SET);
if(-1 == off){
return 1;
}
struct stat stat_buf;
fstat(fd,&stat_buf);
size_t save_size = stat_buf.st_size - off;
//char buf[save_size];
char *buf = malloc(save_size);
if(-1 == read(fd,buf,save_size)){
return 1;
}
off = lseek(fd,atoi(argv[2]),SEEK_SET);
if(-1 == off){
return 1;
}
if(-1 == write(fd,argv[3],strlen(argv[3]))){
return 1;
}
if(-1 == write(fd,buf,save_size)){
return 1;
}
free(buf);
buf = NULL;
}
lseek_write.c:用于执行在特定的位置写入数据的功能
#include
#include
#include
#include
#include
int main(int argc,char* argv[]){
if(4 != argc){
printf("usage:%s n",argv[0]);
return 1;
}
int fd = open(argv[1],O_WRONLY);
if(-1 == fd){
return 1;
}
off_t off = lseek(fd,atoi(argv[2]),SEEK_SET);
if(-1 == off){
return 1;
}
if(-1 == write(fd,argv[3],strlen(argv[3]))){
return 1;
}
}
lseek_read.c:用于在特定的位置进行数据的读取功能
#include
#include
#include
#include
#include
int main(int argc,char* argv[]){
if(4 != argc){
printf("usage:%s n",argv[0]);
return 1;
}
int fd = open(argv[1],O_RDONLY);
if(-1 == fd){
return 1;
}
off_t off = lseek(fd,atoi(argv[2]),SEEK_SET);
if(-1 == off){
return 1;
}
size_t len = atoi(argv[3]);
char buf[len+1];
bzero(buf,len+1);
if(-1 == read(fd,buf,len)){
return 1;
}
printf("%sn",buf);
}
最后
以上就是俏皮大神为你收集整理的linux进程共享内存读写锁,Linux-C-day-5-读写锁的全部内容,希望文章能够帮你解决linux进程共享内存读写锁,Linux-C-day-5-读写锁所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复