同步方式:文件锁flock()/fcntl()、互斥锁与条件变量、信号量、读写锁


在这里插入图片描述


前言

1、文件锁包含劝告式锁强制式锁
劝告式锁:要求每个使用上锁文件的进程都要检查是否有锁存在,并且尊重已有的锁。在一般情况下,内核和系统都不使用建议性锁,它们依靠程序员遵守这个规定。
强制式锁:是由内核执行的锁,当一个文件被上锁进行写入操作的时候,内核将阻止其他任何文件对其进行读写操作。采用强制性锁对性能的影响很大,每次读写操作都必须检查是否有锁存在。

2、使用文件锁的操作函数有flock()和fcntl()
flock():对整个文件。其中包含共享锁和互斥锁
fcntl():对文件区域或整个文件。其中包含读锁(共享锁)和写锁(互斥锁)

本文使用的内容全为劝告式锁。


一、flock()给文件加锁

头文件:#include <sys/file.h>

int flock(int fd, int operation);
success:0    error:-1

fd:打开文件的描述符
operation:
           LOCK_SH:给fd引用的文件加上共享锁  
           LOCK_EX:给fd引用的文件加上互斥锁 
           LOCK_UN:解除fd引用的文件
		   LOCK_NB:非阻塞的请求

eg:
fd1 = open ("test.txt", O_RDWD);
flock (fd1, LOCK_EX);/flock (fd2, LOCK_SH);

①、当一个进程给一个文件加共享锁时,如果另一个进程也给加共享锁这是可以的。如果另外一个进程加的是互斥锁会加锁失败进入阻塞。如果其有OR LOCK_NB则立即返回 -1 errno设为EWOULDBLOCK。
②、当一个进程给一个文件加互斥锁时,另外一个进程不管加共享锁或则互斥锁都会失败进入阻塞。如果其有OR LOCK_NB则立即返回 -1 errno设为EWOULDBLOCK。下表1为总结。

表1:

是否满足请求是否满足请求
当前加上的锁共享锁互斥锁
共享锁
互斥锁

二、fcntl()给记录(文件)加锁

头文件:
#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd, struct flock *lock);
success:0    error:-1

fd:打开文件的描述符
cmd:
	F_GETLK:根据lock参数值,决定是否可以上文件锁
	F_SETLK:设置lock参数值的文件锁
lock:是一个指向flock结构的指针,设置记录锁的具体状态

struct flock
{
	short l_type; / 锁的类型 /
	short l_whence; / 偏移量的起始位置: /
	off_t l_start; / 从l_whence的偏移量 /
	off_t l_len; / 从l_start开始的字节数 /
	pid_t l_pid; / 锁所属进程ID(一般不用) */
}
l_type:		F_RDLCK读锁、F_WRLCK写锁、F_UNLCK删除一把既有锁。
l_whence:SEEK_SETSEEK_CURSEEK_END
l_len: 		start后/前的锁定区域长度。为0时表示从起点开始直至最大
			可能位置为止。

读锁可一直加,写锁只能有一个,其他会进入阻塞。效果同表1

1、write_lock.c 互斥写

写锁是互斥写。

下面的实例是文件写入锁的测试用例,文件名为,wirte_lock.c 。
这里首先创建了一个hello 文件,之后对其上写入锁,最后释放写入锁,代码如下所示

#include<stdio.h>  
#include <unistd.h>  
#include <sys/file.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <stdlib.h>  
#include <unistd.h>
#include <fcntl.h>

int lock_set(int fd,int type)  
{  
    struct flock old_lock,lock;  
    lock.l_whence = SEEK_SET;  
    lock.l_start = 0;  
    lock.l_len = 0;  
    lock.l_type = type;  
    lock.l_pid = -1;  
          
    fcntl(fd,F_GETLK,&lock);  
  
    if(lock.l_type != F_UNLCK)  
    {  
          
        if (lock.l_type == F_RDLCK)    
        {  
            printf("Read lock already set by %d\n",lock.l_pid);  
        }  
        else if (lock.l_type == F_WRLCK)   
        {  
            printf("Write lock already set by %d\n",lock.l_pid);  
        }                         
    }  
      
    lock.l_type = type;  
      
    if ((fcntl(fd,F_SETLKW,&lock)) < 0)  
    {  
        printf("Lock failed : type = %d\n",lock.l_type);  
        return 1;  
    }  
      
    switch (lock.l_type)  
    {  
        case F_RDLCK:  
        {  
            printf("Read lock set by %d\n",getpid());  
        }  
        break;  
        case F_WRLCK:  
        {  
            printf("write lock set by %d\n",getpid());  
        }  
        break;  
        case F_UNLCK:  
        {  
            printf("Release lock by %d\n",getpid());  
            return 1;  
        }  
        break;  
          
        default:  
        break;  
  
    }  
    return 0;  
}
int main(void)  
{    
    int fd;/* 首先打开文件*/  
    fd = open("hello",O_RDWR | O_CREAT, 0644);if(fd < 0)  
    {         
        printf("Open file error\n");      
        exit(1);     
    }      
    lock_set(fd, F_WRLCK);      /* 给文件上写入锁*/    
    getchar();             /*程序暂停,按回车键继续*/      
    lock_set(fd, F_UNLCK);  /* 给文件解锁*/     
    getchar();     
    close(fd);     
    exit(0);      
    return 0;  
} 

开启两个终端,并且在两个终端上同时运行该程序,以达到多个进程操作一个文件的效果。首先在终端1运行,然后在终端2上运行,注意终端二中的第一行输出。
在这里插入图片描述

2、read_lock.c 共享读

读锁是共享读。

接下来的程序是文件读取锁的测试用例,原理和上面的程序一样。只把main函数改成一下内容。文件名为read_lock.c。

int main(void)  
{  
    int fd;fd = open("hello",O_RDWR | O_CREAT, 0644);if(fd < 0)  
    {     
        printf("Open file error\n");  
        exit(1);    
    }  
    lock_set(fd, F_RDLCK);  /* 给文件上读取锁*/  
    getchar();  
    lock_set(fd, F_UNLCK);  /* 给文件解锁*/  
    getchar();  
    close(fd);  
    exit(0);      
    return 0;  
} 

在这里插入图片描述
源码:https://blog.csdn.net/rl529014/article/details/51336161

三、互斥锁与条件变量

线程的互斥锁和条件变量

四、信号量

信号量(无名和有名)

五、读写锁

待记录


  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值