多进程编程——记录锁

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

一、进程间的通信

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结构体定义:

struct flock
{
      short int l_type;            //F_RDLCK共享性读锁定,F_WRLCK独占性写锁定和F_UNLCK释放锁定
      short int l_whence;      // SEEK_SET 文件头 SEEK_CUR当前位置  SEEK_END文件末尾
      __off_t l_start;     
      __off_t l_len;   
      __pid_t l_pid;   
 };


例如给某个文件上写锁:

flock lk;
lk.l_type = F_WRLCK;
lk.l_whence = SEEK_SET;
lk.l_start = 0;
lk.l_len = 0;
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锁的资源,后果是两个傻傻地阻塞下去。(但现在系统会检测死锁,并将出错信息通知其中一个进程)。


你可能感兴趣的:(Linux程序设计)