linux进程共享内存读写锁,Linux-C-day-5-读写锁

本文详细介绍了Linux中的文件锁机制,包括读取锁和写入锁的使用,以及fcntl函数在获取和设置锁中的应用。通过示例代码展示了如何实现文件的加锁、解锁和查看锁状态。同时,提到了锁的类型,如记录锁和文件锁,以及强制性锁和建议性锁的区别。文章还讨论了进程死锁的情况以及lseek函数在文件定位上的作用。
摘要由CSDN通过智能技术生成

读写锁

当一个进程正在读或者修改某个文件的某个部分时,组织其他进程修改同一个文件或者同一个文件的某个区域。对于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 %d\n",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 %s\n",getpid(),argv[1]);

lock(argv[1]);

printf("sleep 1s\n");

sleep(1);

printf("PID:%d lock file %s\n",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("%s\n",buf);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值