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

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);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值