文件锁经常应用于两个方面:
1.一是锁定文件中的临界数据,比如并发投票时文件记录的投票数2.二是利用具有互斥性质的写锁,实现进程的并发控制。

/*使用文件锁*/<F5>
#include <fcntl.h>

fcntl(int fildes,int cmd,struct flock* arg);
cmd:F_GETLK,F_SETLK,F_SETLKW
获得或设置记录锁。
如果出错,所有命令都返回-1.

在fcntl.h中的锁信息结构
struct flock
{
    /*锁类型*/
    short l_type;//取值为读锁F_RDLCK,写锁F_WRLCK,释放锁F_UNLCK
    /*锁区域的开始位置*/
    short l_whence;//锁区域开始地址的相对位置,取值为SEEK_SET,SEEK_CUR,SEEK_END
    long l_start;//锁区域万开始地址的偏移量,与l_whence共同确定锁区域的绝对开始位置
    /*锁区域的长度*/
    long l_len;//如果为0,则表示锁至文件末
    /*拥有锁的进程的ID号*/
    short l_pid;
}

F_GETLK: 在申请文件锁之前查找锁信息。
当制定区域中存在多个文件锁时,fcntl只返回其一。
调用成功返回任意非负整数,否则返回-1
用户提交申请的锁类型,函数返回与该锁类型不兼容的锁信息。
如果提交读锁,fcntl只返回该区域内的写锁而忽略读写。因为读锁只与写锁不兼容
如果提交写锁,fcntl只返回区域内的全部锁信息。因为写锁与其他任意锁都不兼容
如果区域内无文件锁时,arg指向的flock结构的成员l_type将被置为F_UNLCK。

所以使用写锁来测试判断文件某块区域内是否已经有现存锁。

F_SETLK:设置读锁,写锁,清除锁。
调用失败返回-1,否则返回其他值。
如果本进程在该区域已经申请锁,则新锁取代该区域的老锁
如果该区域已被其他进程加锁,而且与新锁不兼容,则函数会调用失败。

F_SETLKW:
为F_SETLK的阻塞版,设置读锁,写锁,清除锁,但是会此阻塞版会导致进程阻塞直到请求被完成为止。而F_SETLK会在执行失败时会立刻返回。

使用流程:将测试锁,申请锁,释放锁三块儿封装成三个函数调用,,封装为库函数会使得以后的使用简单方便许多。
测试锁:查询文件描述符对应文件的锁信息,判断是否有不兼容已存锁

1.封装测试锁函数:void SeekLock(int fd,int start,int len);
功能:判断文件描述符对应的文件从文件开始处偏移start处开始的len字节区域中的锁信息:
void SeekLock(int fd,int start,int len)
{
    struct flock arg;
    arg.l_type = F_WRLCK;
    arg.l_whence = SEEK_SET;
    arg.l_start = start;
    arg.l_len = len;
    if(fcntl(fd,F_GETLK,&arg) == -1)
    {
        fprintf(stderr,"See Lock failed.\n");
    }
    else if(arg.l_type == F_UNLCK)
    {
        fprintf(stderr,"No lock from %d to %d\n",start,len);
    }
    else if(arg.l_type == F_WRLCK)
    {
        fprintf(stderr,"Write Lock From %d to %d,id = %d\n",start,len,arg.l_pid);
    }
    else if(arg.l_type == F_RDLCK)
    {
        fprintf(stderr,"Read Lock From %d To %d,id = %d\n",start,len,arg.l_pid);
    }
}

2.封装申请读锁函数
void GetReadLock(int fd,int start,int len);
已阻塞模式在文件描述符对应的文件中申请共享读锁,锁定的区域为从偏移start处开始的len字节长度大小的区域

void GetReadLock(int fd,int start,int len)
{
    struct flock arg;
    arg.l_type = F_RDLCK;
    arg.l_whence = SEEK_SET;
    arg.l_start = start;
    arg.l_len = len;
    if(fcntl(fd,F_SETLKW,&arg) == -1)
    {
        fprintf(stderr,"[%d] Set Read Lock failed.\n",getpid());
    }
    else
        fprintf(stderr,"[%d] Set Read Lock From %d To %d\n",getpid(),start,len);
}

3.封装申请设置写锁函数
互斥写锁申请函数GetWriteLock,原型为:
void GetWriteLock(int fd,int start,int len)
功能:已阻塞模式在文件描述符对应的文件中申请互斥写锁,锁定的区域为从偏移start处开始的len字节长度大小的区域。

void GetWriteLock(int fd,int start,int len)
{
    struct flock arg;
    arg.l_type = F_WRLCK;
    arg.l_whence = SEEK_SET;
    arg.l_start = start;
    arg.l_len = len;
    if(fcntl(fd,F_SETLKW,&arg) == -1)
    {
        fprintf(srderr,"[%d] Set Write Lock failed.\n",getpid());
    }
    else
        fprintf(stderr,"[%d] Set Write Lock %d To %d\n",getpid(),start,len);
}

}
}

4.释放锁
void ReleaseLock(int fd,int start,int len)
{
    struct flock arg;
    arg.l_type = F_UNLCK;
    arg.l_whence = SEEK_SET;
    arg.l_start = start;
    arg.l_len = len;
    if(fcntl(fd,F_SETLKW,&arg) == -1)
    {
        fprintf(stderr,"[%d] Unlock failed.\n",getpid());
    }
    else
        fprintf(stderr,"[%d]Unlock From %d To %d\n",getpid(),start,len);
}

最新文章

  1. ubuntu下配置vpn
  2. Ubuntu下两个gcc版本切换
  3. WinForm中异步加载数据并使用进度条
  4. Nginx基础知识之————Nginx 环境的搭建?
  5. Javascript里的那些距离们
  6. BZOJ 2299 向量
  7. C++成员变量初始化顺序问题
  8. LeetCode OJ学习
  9. Linux共享库两种加载方式简述
  10. OpenCV——改变图像大小
  11. 网络流——增广路算法(dinic)模板 [BeiJing2006]狼抓兔子
  12. 客户端数据持久化解决方案: localStorage
  13. 返璞归真 asp.net mvc (5) - Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test
  14. android 删除SD卡或手机的缓存图像和文件夹
  15. 通过一个tomcat端口访问多个tomcat项目 tomcat转发
  16. nginx.conf 中php-ftp配置
  17. mybatis 一对多的注入 指的是连表查询时候 将不同的查询结果以列表存储对象形式 注入进去 多对一指的是 查询多条结果但都是一样的 只需注入一条
  18. 猜数字小游戏,很naive......
  19. 洛谷P4495 奇怪的背包 [HAOI2018] 数论
  20. [C#]获取连接MySql数据库及常用的CRUD操作

热门文章

  1. Less 的用法
  2. ES6----Proxy(一)
  3. 软件团队项目第一次Sprint评价(评价人:张家军)
  4. mysql 官方集群
  5. ResNet笔记
  6. 【CS231N】3、Softmax分类器
  7. P4安装
  8. 开发模式 MVC、MVP、MVVM和MVX框架模式
  9. [学习]Windows server 使用控制台时容易卡死的解决方法
  10. 半夜思考之查漏补缺 , Spring 中 Bean 之间的依赖问题