fcntl应用于文件记录锁

参考文章:

http://blog.mcuol.com/User/zhl168/Article/11232_1.htm

http://blog.csdn.net/bical/archive/2008/10/03/3014731.aspx

 

fcntl()用来操作文件描述词的一些特性。参数fd代表欲设置的文件描述词,参数cmd代表欲操作的指令。 
有以下几种情况: 
F_DUPFD用来查找大于或等于参数arg的最小且仍未使用的文件描述词,并且复制参数fd的文件描述词。执行成功则返回新复制的文件描述词。请参考dup2()。F_GETFD取得close-on-exec旗标。若此旗标的FD_CLOEXEC位为0,代表在调用exec()相关函数时文件将不会关闭。 
F_SETFD 设置close-on-exec 旗标。该旗标以参数arg 的FD_CLOEXEC位决定。 
F_GETFL 取得文件描述词状态旗标,此旗标为open()的参数flags。 
F_SETFL 设置文件描述词状态旗标,参数arg为新旗标,但只允许O_APPEND、O_NONBLOCK和O_ASYNC位的改变,其他位的改变将不受影响。 
F_GETLK 取得文件锁定的状态。 
F_SETLK 设置文件锁定的状态。此时flcok 结构的l_type 值必须是F_RDLCK、F_WRLCK或F_UNLCK。如果无法建立锁定,则返回-1,错误代码为EACCES 或EAGAIN。 
F_SETLKW F_SETLK 作用相同,但是无法建立锁定时,此调用会一直等到锁定动作成功为止。若在等待锁定的过程中被信号中断时,会立即返回-1,错误代码为EINTR。参数lock指针为flock 结构指针,定义如下 
struct flcok 

short int l_type; /* 锁定的状态*/ 
short int l_whence;/*决定l_start位置*/ 
off_t l_start; /*锁定区域的开头位置*/ 
off_t l_len; /*锁定区域的大小*/ 
pid_t l_pid; /*锁定动作的进程*/ 
}; 
l_type 有三种状态: 
F_RDLCK 建立一个供读取用的锁定 
F_WRLCK 建立一个供写入用的锁定 
F_UNLCK 删除之前建立的锁定 
l_whence 也有三种方式: 
SEEK_SET 以文件开头为锁定的起始位置。 
SEEK_CUR 以目前文件读写位置为锁定的起始位置 
SEEK_END 以文件结尾为锁定的起始位置。 
  
返回值 成功则返回0,若有错误则返回-1,错误原因存于errno.

 

 

示例:

锁设置子函数:
/*
 * 设置记录锁子函数lock_set.c
 *
 * 记录锁分为读取锁和写入锁,其中读取锁又称为共享锁,可以使多个
 * 进程都能够在文件的同一部分建立读取锁。而写入锁又称为互斥锁,
 * 在任何时刻只能有一个进程在文件的某个部分建立写入锁。当然,在
 * 文件的同一部分不能同时建立读取锁和写入锁。
 *
 * fcntl的lock结构如下所示:
 * struct flock {
 * short l_type;
 * off_t l_start;
 * short l_whence;
 * off_t l_len;
 * pid_t l_pid;
 * }
 *
 * 技巧:为加锁整个文件,通常的方法是将l_start说明为0,l_whence
 * 说明为SEEK_SET,l_len说明为0。
 */

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

void print_lock(struct flock lock)
{
  printf(" -----------------------------/n");

  if (lock.l_type == F_RDLCK) {
  printf("/tl_type: F_RDLCK/n");
  }
  else if (lock.l_type == F_WRLCK) {
  printf("/tl_type: F_WRLCK/n");
  }
  else if (lock.l_type == F_UNLCK) {
  printf("/tl_type: F_UNLCK/n");
  }

  printf("/tl_start: %d/n", (int)lock.l_start);

  if (lock.l_whence == SEEK_SET) {
  printf("/tl_whence: SEEK_SET/n");
  }
  else if (lock.l_whence == SEEK_CUR) {
  printf("/tl_whence: SEEK_CUR/n");
  }
  else if (lock.l_whence == SEEK_END) {
  printf("/tl_whence: SEEK_END/n");
  }

  printf("/tl_len: %d/n", (int)lock.l_len);

  printf(" -----------------------------/n");
}

void lock_set(int fd, int type)
{
  struct flock lock;

  /*赋值lock结构体,加锁整个文件*/
  lock.l_whence = SEEK_SET;
  lock.l_start = 0;
  lock.l_len = 0;

  while (1) {
  lock.l_type = type;

  /*
  * 根据不同的type来给文件加锁或解锁,
  * 如果成功,则返回0,失败则返回-1。
  * 举例:如果一个文件原来已经建立了互斥锁,那么再调用fcntl
  * 建立锁就会失败,返回-1。
  */
  if ((fcntl(fd, F_SETLK, &lock)) == 0) {
  /*如果是共享锁*/
  if (lock.l_type == F_RDLCK) {
  printf("read only set by %d/n", getpid());
  }
  /*如果是互斥锁*/
  else if (lock.l_type == F_WRLCK) {
  printf("write lock set by %d/n", getpid());
  }
  else if (lock.l_type == F_UNLCK) {
  printf("release lock by %d/n", getpid());
  }
  print_lock(lock);
  return;
  }
  else {
  /*
  * 获得lock的描述,也就是将文件fd的加锁信息存入到lock结构中
  * 如果成功则返回0
  * 如果失败则返回-1
  */
  if ((fcntl(fd, F_GETLK, &lock)) == 0) {
  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);
  }
  getchar();
  }
  }
  else {
  printf("cannot get the description of struck flock./n");
  }
  }
  }
}


读取锁:
/*
 * 测试文件读取锁
 */

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

void lock_set(int, int);

void die(char *msg)
{
  perror(msg);
  exit(1);
}

int open_file(void)
{
  int fd;

  if ((fd = open("/tmp/hello.c", O_CREAT | O_TRUNC | O_RDWR, 0666)) < 0) {
  die("open error");
  }
  else {
  printf("Open file: hello.c %d/n", fd);
  }

  return fd;
}

void close_file(int fd)
{
  if (close(fd) < 0) {
  die("close error");
  }
  else {
  printf("Close file: hello.c/n");
  }
}

int main(void)
{
  int fd;

  fd = open_file();

  /*给文件加写入锁*/
  lock_set(fd, F_RDLCK);
  /*等待键盘任意键触发*/
  getchar();
  /*给文件解锁*/
  lock_set(fd, F_UNLCK);
  getchar();
  close_file(fd);

  return 0;
}


写入锁:
/*
 * 测试文件写入锁
 */

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

void lock_set(int, int);

void die(char *msg)
{
  perror(msg);
  exit(1);
}

int open_file(void)
{
  int fd;

  if ((fd = open("/tmp/hello.c", O_CREAT | O_TRUNC | O_RDWR, 0666)) < 0) {
  die("open error");
  }
  else {
  printf("Open file: hello.c %d/n", fd);
  }

  return fd;
}

void close_file(int fd)
{
  if (close(fd) < 0) {
  die("close error");
  }
  else {
  printf("Close file: hello.c/n");
  }
}

int main(void)
{
  int fd;

  fd = open_file();

  /*给文件加写入锁*/
  lock_set(fd, F_WRLCK);
  /*等待键盘任意键触发*/
  getchar();
  /*给文件解锁*/
  lock_set(fd, F_UNLCK);
  getchar();
  close_file(fd);

  return 0;
}


Makefile源文件:

CC = gcc
OBJS = fcntl_write fcntl_read
CFLAGS = -Wall -g

all: $(OBJS)

fcntl_write: fcntl_write.c lock_set.c
  $(CC) $(CFLAGS) $^ -o $@
fcntl_read: fcntl_read.c lock_set.c
  $(CC) $(CFLAGS) $^ -o $@

.PHONY: clean
clean:
  rm -rf $(OBJS)



测试结果:
[armlinux@lqm fcntl]$ ./fcntl_read 
Open file: hello.c 3
read only set by 12398
  -----------------------------
  l_type: F_RDLCK
  l_start: 0
  l_whence: SEEK_SET
  l_len: 0
  -----------------------------

release lock by 12398
  -----------------------------
  l_type: F_UNLCK
  l_start: 0
  l_whence: SEEK_SET
  l_len: 0
  -----------------------------

Close file: hello.c
[armlinux@lqm fcntl]$ ./fcntl_write 
Open file: hello.c 3
write lock set by 12399
  -----------------------------
  l_type: F_WRLCK
  l_start: 0
  l_whence: SEEK_SET
  l_len: 0
  -----------------------------

release lock by 12399
  -----------------------------
  l_type: F_UNLCK
  l_start: 0
  l_whence: SEEK_SET
  l_len: 0
  -----------------------------

Close file: hello.c

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值