多进程读写锁

本文深入探讨了多进程编程中的核心技术——进程间的同步机制,包括进程间的通信方式如管道、信号量、共享内存等,以及互斥访问手段如条件变量、信号量、读写锁等。特别介绍了记录锁的工作原理及其在内核中的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多进程编程的核心技术是进程间的同步——通信与互斥访问

一、进程间的通信

1、管道

2、System V信号量

3、共享内存

4、消息队列

5、信号 

6、套接字

二、进程间对资源的互斥访问

条件变量
信号量
读写锁(记录锁)
自旋锁
原子锁(顺序锁)



记录锁:

int fcntl(int fd, int cmd, struct flock* flockptr);

cmd可以是F_GETLK、F_SETLK或F_SETLKW。

F_GETLK:查看是否有其它进程锁与flockptr所描述的冲突,如果存在冲突,则将其信息写到flockptr。反之只改写flockptr.l_type为F_UNLCK。

F_SETLK:设置或清楚flockptr描述的锁。若跟已有的锁冲突,则返回-1并将errno设置为EACCES或者EAGAIN。

F_SETLKW:作用同上。但若有冲突的锁,则阻塞等待直到与其它锁冲突消失或被信号中断。被信号中断返回时,返回-1并设置errno为EINTR。

flock结构体定义:

[cpp]  view plain copy
  1. struct flock  
  2. {  
  3.       short int l_type;            //F_RDLCK共享性读锁定,F_WRLCK独占性写锁定和F_UNLCK释放锁定  
  4.       short int l_whence;      // SEEK_SET 文件头 SEEK_CUR当前位置  SEEK_END文件末尾  
  5.       __off_t l_start;       
  6.       __off_t l_len;     
  7.       __pid_t l_pid;     
  8.  };  


例如给某个文件上写锁:

[cpp]  view plain copy
  1. flock lk;  
  2. lk.l_type = F_WRLCK;  
  3. lk.l_whence = SEEK_SET;  
  4. lk.l_start = 0;  
  5. lk.l_len = 0;  
  6. fcntl(fd,F_SETLK,&lk);  


理解:

1、当文件无锁的时候,任何进程都能上读锁或写锁。

2、当文件被A进程上了读锁的时候,其它任何进程都可以上读锁,但不能上写锁!(很容易理解,A进程上了读锁(需要读此文件),此时其它进程也上读锁不会对A做成影响。但如果其它进程要上写锁(需要对文件进行写操作),那会影响到A的进行,因为写操作会修改原文件!!)

3、当文件被A进程上了写锁,其它任何进程都不能上写或读锁。(因为A进程上写锁(代表需要写此文件),如果此时其它进程读此文件的话必定受影响,其它进程写操作的话,双方都受影响。)


内核中理解记录锁:

在系统在每个文件vNode中(每个打开文件都有一个V节点结构)有一个记录锁链表:

链表中元素有四个字段:

1、锁的flag。

2、锁的起始偏移量(绝对偏移量)。

3、锁的长度(为0则代表直到文件最后——跟随文件大小而改变)。

4、进程ID号。

注意第4个字段,由于文件锁参数是记录在系统V节点表里的记录锁链表里的,而fork子进程和父进程具有不同的进程ID号,因此子进程自然也不继承父进程的文件锁。同理exec

前后具有相同进程ID号,因此继承相同的文件锁(除非文件标记了close_on_exec,exec之后自动关闭文件,自然同时关闭文件锁)。


强制锁和建议锁:

1、强制锁会影响到其它进程的读写操作:open、read、write等。

例如:A进程对某文件某部分加了强制写锁,其它进程都不能对那部分进行上锁或读写。

2、建议锁只会影响其它进程的上锁操作,而不会限制实际的IO。

例如:A进程对某文件某部分加了强制写锁,其它进程不能对那部分上锁,但还是可以对其读写的(但这样无视锁的做法是不可取的)

注意:在linux中fcntl默认上的是建议锁!!!


协同进程:

建议锁并不强制限制I/O,因此当所有进程都自觉使用建议锁,并根据建议锁的情况考虑是否读写,才能发挥建议锁的作用。这样些遵循建议锁的进程称为协同进程。


记录锁的关闭:

无论用dup复制多少个文件描述符,只要有其中一个被close了,则此进程的所有锁都被关闭了。


记录锁引发的问题:

死锁问题:两个进程互相阻塞等待对方持有的锁,最严重后果是两进程永远阻塞成死锁。例如:A进程有A锁,B进程有B锁,A试图用F_SETLKW设锁到有B锁的资源,同时B也使用F_SETLKW设锁要有A锁的资源,后果是两个傻傻地阻塞下去。(但现在系统会检测死锁,并将出错信息通知其中一个进程)。

简单高效的跨进程锁,支持读写锁分离,  也可以用于文件锁Getting startedIn your build.gradle:allprojects {     repositories {         maven { url 'https://jitpack.io' }     } } dependencies {     implementation 'com.github.pqpo:PLock:{last-version}'}UsageStep 1. get a default PLock object, and you can also create one by yourself.Step 2. acquire locks.Step 3. unlock.Step 4. release if necessary.For example:PLock pLock = PLock.getDefault();// OR you can also use it as a file lock:// PLock pLock = new PLock(file);pLock.lock();  try {    // to do something...} catch (Exception e) {    // errors} finally {     pLock.unlock();  }// in non-blocking modeif(pLock.tryLock()) {   try {       // to do something...    } catch (Exception e) {       // errors    } finally {        pLock.unlock();     } }  // non-block read lockif(pLock.tryReadLock()) {    // to do something...}  // non-block write lockif(pLock.tryWriteLock()) {    // to do something...}  // etc.// pLock.release();Play with samples, have fun!You can clone this repository, then run 'debug' build variant and 'second' build variant, after that you can see two applications running on your phone which named PLock-FirstProcess and PLock-SecondProcess.Or download PLock-FirstProcess and PLock-SecondProcess.PLock-first-processPLock-second-process
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值