Linux系统上的文件锁主要分为协同锁(advisory lock)和强制锁(mandatory lock)。在Linux上使用的文件锁大部分为协同锁,而且使用强制锁的时候也要检查系统是否支持强制锁.

1)协同锁

协同锁要求参与操作的进程之间协同合作。假设进程“A”获得一个WRITE锁,并开始向文件中写入内容;此时,进程“B”并没有试图获取一个锁,它仍然可以打开文件并向文件中写入内容。在此过程中,进程“B”就是一个非合作进程。如果进程“B”试图获取一个锁,那么整个过程就是一个合作的过程,从而可以保证操作的“序列化”。

只有当参与操作的进程是协同合作的时候,协同锁才能发挥作用。协同锁有时也被称为“非强制”锁。有些程序利用诸如 FIlENAME.lock 的文件锁文件,然后简单地测试此类文件是否存在。这种方法显然不太好,因为当产生文件的进程被杀后,锁文件依然存在,这样文件也许会被永久锁住。

UUCP中把产生文件的进程号PID存入文件,但这样做仍然不保险,因为PID的利用是回收型的。这里是三个文件锁函数:

lockf();

flock()是从BSD中衍生出来的,但目前在大多数UNIX系统上都能找到,在单个主机上flock()简单有效,但它不能在NFS上工作。Perl中也有一个有点让人迷惑的flock()函数,但却是在perl内部实现的。

fcntl()是唯一的符合POSIX标准的文件锁实现,所以也是唯一可移植的。它也同时是最强大的文件锁--也是最难用的。在NFS文件系统上,fcntl()请求会被递交给叫rpc.lockd的守护进程,然后由它负责和主机端的lockd对话,和flock()

不同,fcntl()可以实现记录层上的封锁。

lockf()只是一个简化了的fcntl()文件锁接口。

无论你使用哪一种文件锁,请一定记住在锁生效之前用sync来更新你所有的文件输入/输出。

2)强制锁

强制锁不需要参与操作的进程之间保持协同合作。它利用内核来查检每个打开、读取、写入操作,从而保证在调用这些操作时不违反文件上的锁规则。关于强制锁的更多信息,可以在kernal.org上找到。

为了使能Linux中的强制锁功能,你需要在文件系统级别上打开它,同时在单个文件上打开它。其步骤是:

(1)挂载文件系统时使用“-omand”参数。

(2)对于要打开强制锁功能的文件lock_file,必须打开set-group-ID位,关闭group-execute位。(选择此方法的原因是,当你关闭group-execute时,设置set-group-ID就没有实际的意义了)。

检测系统是否支持强制锁的代码如下:#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

volatile sig_atomic_t sigflag;

int pfd1[2], pfd2[2];

sigset_t newmask, oldmask, zeromask;

void err_doit(int errnoflag, const char *fmt, va_list ap)

{

int errno_save;

char buf[4096];

errno_save = errno;

vsprintf(buf, fmt, ap);

if (errnoflag)

sprintf(buf+strlen(buf), ": %s", strerror(errno_save));

strcat(buf, "/n");

fflush(stdout);

fputs(buf, stderr);

fflush(stderr);

return;

}

void err_sys(const char *fmt, ...)

{

va_list ap;

va_start(ap, fmt);

err_doit(1, fmt, ap);

va_end(ap);

exit(1);

}

void sig_usr(int signo)

{

sigflag = 1;

return;

}

TELL_WAIT()

{

if (signal(SIGUSR1, sig_usr) == SIG_ERR) /*SIGUSR1 为用户自定义信号*/

err_sys("signal(SIGINT) error");

if (signal(SIGUSR2, sig_usr) == SIG_ERR)

err_sys("signal(SIGQUIT) error");

sigemptyset(&zeromask);

sigemptyset(&newmask);

sigaddset(&newmask, SIGUSR1);

sigaddset(&newmask, SIGUSR2);

/*阻塞 SIGUSR1 和 SIGUSR2 并且保存当前信号掩码*/

if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)

err_sys("SIG_BLOCK error");

}

void WAIT_PARENT(void)

{

while( sigflag == 0)

sigsuspend(&zeromask); /*suspend()取消了所有信号屏蔽,等待父进程发来信号*/

sigflag = 0;

/*恢复信号掩码*/

if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)

err_sys("SIG_SETMASK error");

}

int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)

{

struct flock lock;

lock.l_type = type;

lock.l_start = offset;

lock.l_whence = whence;

lock.l_len = len;

return( fcntl(fd, cmd, &lock) );

}

void set_fl(int fd, int flags)

{

int val;

if ( (val = fcntl(fd, F_GETFL, 0)) < 0)

err_sys("fcntl F_GETFL error");

val |= flags; /*置标志*/

if (fcntl(fd, F_SETFL, val) < 0)

err_sys("fcntl F_SETFL error");

}

void err_ret(const char *fmt, ...)

{

va_list ap;

va_start(ap, fmt);

err_doit(1, fmt, ap);

va_end(ap);

return;

}

int main(void)

{

int fd;

pid_t pid;

char buff[5];

struct stat statbuf;

if ( (fd = open("templock", O_RDWR | O_CREAT | O_TRUNC, 0644)) < 0)

err_sys("open error",buff);

if (write(fd, "abcdef", 6) != 6)

err_sys("write error");

/*打开 set-group-ID(s-gid),并关闭组执行权限*/

if (fstat(fd, &statbuf) < 0)

err_sys("fstat error");

if (fchmod(fd, (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0)

err_sys("fork error");

TELL_WAIT();

if ( (pid = fork()) < 0) {

err_sys("fork error");

} else if (pid > 0) { /*父进程*/

/*整个文件写锁*/

if (lock_reg(fd, F_SETLK, F_WRLCK, 0, SEEK_SET, 0) < 0)

err_sys("write_lock error");

kill(pid, SIGUSR1); /*给子进程发送信号告知锁完成*/

if (waitpid(pid, NULL, 0) < 0)

err_sys("waitpid error");

} else {

WAIT_PARENT(); /*等待父进程设置锁*/

set_fl(fd, O_NONBLOCK);

if (lock_reg(fd, F_SETLK, F_RDLCK, 0, SEEK_SET, 0) != -1)

err_sys("child: read_lock succeeded");

printf("read_lock of already-locked region return %d/n", errno);

if (lseek(fd, 0, SEEK_SET) == -1)

err_sys("lseek, error");

if (read(fd, buff, 2) < 0)

err_ret("read failed (mandatory locking wroks)");

else

printf("read OK (no mandatory locking), buff = %2.2s/n", buff);

}

exit(0);

}

linux c语言文件锁,Linux下glibc库文件锁:协同锁(advisory lock)和强制锁(mandatory lock)...相关推荐

  1. Linux下glibc库说明一

    一.glibc库的说明: 1. glibc库介绍: glibc是GNU发布的libc库,即C运行库.glibc是Linux系统中最底层的API,几乎其它任何运行库都会依赖于glibc.glibc除了封 ...

  2. linux 卸载glibc,CentOS下glibc库卸载恢复

    CentOS下glibc库卸载恢复 CentOS glibc 在yum update或是手动更新glibc过程中,手残卸载glibc之后系统将缺失一些核心函数如cd/ls/cp等等,几乎废掉. 在保持 ...

  3. linux c语言 ppt,Linux下C语言编程.ppt

    Linux下C语言编程 Linux中C语言的重要性 Linux和C天生有不解之缘. Linux操作系统的内核主要是用C写的,另外Linux下的很多软件也是用C写的,特别是一些著名的服务软件,比如MyS ...

  4. linux c语言 密码,Linux 双因子认证(密码+PIN)C语言版

    Linux 双因子认证(密码+PIN)C语言版.md 关键字 Linux C语言 PAM SSH 2 Two Multi Factor Authentication Login 双因子 多因子 密保 ...

  5. linux电脑接电视,Ubuntu下如何给通过HDMI连接电视机的计算机强制设置1920*1080分辨率...

    Ubuntu下如何给通过HDMI连接电视机的计算机强制设置1920*1080分辨率 发布时间:2014-06-20 10:17:35来源:红联作者:velcbo xrandr只能设置一些已经存在的,如 ...

  6. linux c语言工具,Linux下C语言编程环境的工具.doc

    Linux下C语言编程环境的工具 Linux下C语言编程环境的工具 Linux下C语言编程环境的工具 要想在Linux下进行C语言编程,首先得搭建好一个编程环境.这里分别说明一下几个非常有用的软件包. ...

  7. linux c语言 ppt,linux操作系统下c语言编程入门.ppt

    linux操作系统下c语言编程入门.ppt Linux操作系统下C语言编程入门 CNT Linux操作系统简介基础知识进程介绍文件操作时间概念消息管理线程操作网络编程Linux下C开发工具介绍 一 L ...

  8. linux c语言 信号,linux下基于C语言的信号编程实例

    搜索热词 本文实例讲述了linux下基于C语言的信号编程方法.分享给大家供大家参考.具体如下: #include #include #include #include #include void si ...

  9. debian linux修改语言,Debian Linux系统下英文系统切换为中文

    如果我们在安装debian基本系统的时候选择了英文的语言环境,之后又希望将它改为中文,我们需要完成下面几方面的工作. 设置locale 如果没有安装locale工具,则首先要安装它,然后执行 #dpk ...

最新文章

  1. TIOBE 5 月编程语言排行榜:Python、C++竞争白热化,Objective-C已沦为小众语言
  2. 21张让你代码能力突飞猛进的速查表(神经网络、机器学习、可视化等)
  3. 百度成立国内首个深度学习教育联盟,将制定行业标准
  4. SLF4j、log4j管理系统日志(Maven)
  5. 化工原理少学时答案解析_化工原理少学时知识点
  6. 的拼音怎么改正_「我就退出家长群怎么了?」:多少中年父母的崩溃,从家长群开始...
  7. php mqtt qos,Mqtt Qos 深度解读
  8. ·必须《飞鸽~飞鸽传书》
  9. 交换机的质量害死人呀!
  10. 无限法则无法连接服务器内容,无限法则链接不了服务器
  11. 项目成本管理---控制成本
  12. 《哥德尔、艾舍尔、巴赫——集异璧之大成》
  13. 十大品牌去除甲醛净化器 哪个品牌好
  14. 集合点 java协议_LR插入集合点rendezvous
  15. 单实例安装elastic和启动报错解决
  16. 前端的图片优化的6种方案
  17. Ubuntu nautilus 快速打开文件浏览器
  18. Think Pad L480充电蓝屏问题解决
  19. android的虚拟机
  20. Valgrind 的下载安装和使用 (centos7.6, 其他linux应该类同)

热门文章

  1. 什么是中间层,什么是三层网络结构
  2. Centos系统mysql 忘记root用户的密码
  3. layui ztree 实现下拉树
  4. 第25章 认识更多Spring MVC家族成员(一)
  5. Python软件编程等级考试三级——20210905
  6. 具有多个项目的可访问拖放
  7. java 实现 公式计算
  8. 文件夹下的图片名字进行重命名--批量操作
  9. axios和ajax的区别是什么
  10. 10.25软件测试学习总结