linux系统编程之文件与I/O(六):fcntl 函数与文件锁

 

 

 分类:
linux系统编程(19) 

一、fcntl函数

功能:操纵文件描述符,改变已打开的文件的属性

int fcntl(int fd, int cmd, ... /* arg */ );

 

cmd的取值可以如下:

复制文件描述符
F_DUPFD (long)


设置/获取文件描述符标志
F_GETFD (void)
F_SETFD (long)


设置/获取文件状态标志
F_GETFL (void)
F_SETFL (long)


获取/设置文件锁
F_GETLK
F_SETLK,F_SETLKW

 

其中复制文件描述符可参见《linux系统编程之文件与I/O(五):打开文件的内核结构file和重定向》,文件描述符的标志只有一个即FD_CLOEXEC,设置/获取文件描述符标志看这里。下面先来看设置/获取文件状态标志。

F_SETFL:

On Linux  this  command can change only the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags.

示例程序如下:

 

C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
 
/*************************************************************************
    > File Name: file_fcntl.c
    > Author: Simba
    > Mail: dameng34@163.com
    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
 ************************************************************************/
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

void set_flag(int, int);
void clr_flag(int, int);

int main(int argc, char *argv[])
{
    char buf[1024] = {0};
    int ret;
    /*
        int flags;
        flags = fcntl(0, F_GETFL, 0);
        if (flags == -1)
            ERR_EXIT("fcntl get flag error");
        ret = fcntl(0, SETFL, flags | O_NONBLOCK); //设置为非阻塞,但不更改其他状态
        if (ret == -1)
            ERR_EXIT("fcntl set flag error");
    */
    set_flag(0, O_NONBLOCK);
    ret = read(0, buf, 1024);
    if (ret == -1)
        ERR_EXIT("read error");

    printf("buf=%s\n", buf);
    return 0;
}

void set_flag(int fd, int flags)
{
    int val;
    val = fcntl(fd, F_GETFL, 0);
    if (val == -1)
        ERR_EXIT("fcntl get flag error");
    val |= flags;
    if (fcntl(fd, F_SETFL, val) < 0)
        ERR_EXIT("fcntl set flag error");
}

void clr_flag(int fd, int flags)
{
    int val;
    val = fcntl(fd, F_GETFL, 0);
    if (val == -1)
        ERR_EXIT("fcntl get flag error");
    val &= ~flags;
    if (fcntl(fd, F_SETFL, val) < 0)
        ERR_EXIT("fcntl set flag error");
}
测试输出:

 

simba@ubuntu:~/Documents/code/linux_programming/APUE/File_IO$ ./file_fcntl 
read error: Resource temporarily unavailable

因为将标准输入的状态更改为非阻塞,则read不会阻塞等待输入而立即返回错误,errno将被置为EAGAIN,即可以重新尝试。

 

二、文件锁结构体

struct flock {
...
short l_type;       /* Type of lock: F_RDLCK,
        F_WRLCK, F_UNLCK */
short l_whence; /* How to interpret l_start:
                                   SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start;       /* Starting offset for lock */
off_t l_len;         /* Number of bytes to lock */
pid_t l_pid;        /* PID of process blocking our lock
                                   (F_GETLK only) */
     ...
};

文件锁的类型只有两种,一种是写锁也叫排他锁,一种是读锁也就共享锁,可以有多个进程各持有一个读锁,但只能有一个进程持有写锁,只有对文件有对应的读写权限才能施加对应的锁类型。中间三个参数 l_whence,  l_start, l_len 决定了被锁定的文件范围。当fcntl 函数的cmd为F_GETLK时,flock 结构体的 l_pid 参数会返回持有写锁的进程id。进程退出或者文件描述符被关闭时,会释放所有的锁。

 

示例程序如下:

 

C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 
/*************************************************************************
    > File Name: file_flock.c
    > Author: Simba
    > Mail: dameng34@163.com
    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
 ************************************************************************/
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)


int main(int argc, char *argv[])
{
    int fd;
    fd = open("test2.txt", O_CREAT | O_RDWR | O_TRUNC, 0664);
    if (fd == -1)
        ERR_EXIT("open error");
    /* 只有对文件有相应的读写权限才能施加对应的文件锁 */
    struct flock lock;
    memset(&lock, 0, sizeof(lock));
    lock.l_type = F_WRLCK; // 排他锁,即不允许其他进程再对其加任何类型的锁,但读锁(共享锁)允许
    lock.l_whence = SEEK_SET;
    lock.l_start = 0; //从文件开头开始锁定
    lock.l_len = 0; // 文件全部内容锁住

    if (fcntl(fd, F_SETLK, &lock) == 0)
    {
        /* 若为F_SETLKW,这时如果锁已经被其他进程占用,则此进程会阻塞直到其他进程释放锁*/
        printf("lock success\n");
        printf("press any key to unlock\n");
        getchar();
        lock.l_type = F_UNLCK;
        if (fcntl(fd, F_SETLK, &lock) == 0)
            printf("unlock success\n");
        else
            ERR_EXIT("unlock fail");
    }
    else
        ERR_EXIT("lock fail");

    return 0; //进程退出会对所有文件解锁
}

 

测试如下:

我们先在一个 终端执行程序:

simba@ubuntu:~/Documents/code/linux_programming/APUE/File_IO$ ./file_flock 
lock success
press any key to unlock

 

现在文件已经被锁住了,而且没有按下任何按键,所以卡在这里,也还没解锁,接着在另一个终端再次执行同个程序:

simba@ubuntu:~/Documents/code/linux_programming/APUE/File_IO$ ./file_flock 
lock fail: Resource temporarily unavailable

会立即返回错误,因为我们希望施加的是排他锁,而现在前面一个进程正在占用写锁还没释放,所以尝试施加锁失败,而如果fcntl 函数的cmd 设置为 F_SETLKW,即带w的版本,则此进程会一直阻塞直到前面一个进程释放了锁。

 

参考:《APUE》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/542572.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python 使用异常函数_您如何测试Python函数引发异常?

python 使用异常函数This article elaborates on how to implement a test case for a function that raises an exception. 本文详细介绍了如何为引发异常的函数实现测试用例 。 Consider the following function: 考虑以下功能&#xff1a; import redef check_email_forma…

php 远程图片合拼,PHP实现将几张照片拼接到一起的合成图片功能【便于整体打印输出】...

本文实例讲述了PHP实现将几张照片拼接到一起的合成图片功能。共享给大家供大家参考&#xff0c;详细如下&#xff1a;/*** 作品合成程序* 针对单面&#xff0c;封面不做特殊处理*/$src_path $argv[1]; // php该文件&#xff0c;第一个参数是文件夹名(作品集)&#xff0c;可相对…

bandizip最后一个无广告版本_如果非要选择一款压缩软件的话——Bandizip

全世界只有不到0.00~1 % 的人关注了我们得到你的关注是小帮的幸运压缩解压软件是电脑一个必备软甲&#xff0c;前面的文章介绍了一款开源小巧无广告的压缩解压软件windows工具软件选择之压缩软件——7-Zip&#xff0c;如果有人用不惯的话可以试试今天的这款。Bandizip 是一款来…

[MVC学习笔记]1.项目结构搭建及单个类在各个层次中的实现

新人刚开始学习ASP.NET MVC&#xff0c;若有不足之处希望能得到您的指点&#xff0c;不胜感激&#xff01; 先来一张项目的层级结构图: Model&#xff1a;模型层&#xff0c;主要是各种类型、枚举以及ORM框架&#xff0c;框架完成数据库和实体类的映射。项目中选用了微软的开源…

日期getUTCSeconds()方法以及JavaScript中的示例

JavaScript日期getUTCSeconds()方法 (JavaScript Date getUTCSeconds() method) getUTCSeconds() method is a Dates class method and it is used to get seconds from the current time according to the UTC (Universal time coordinated). getUTCSeconds()方法是Date的类方…

dedecms 在模板里引入php文件夹,dedecms如何添加并引入php文件

前言&#xff1a;有些时候我们需要创建一些单独的PHP文件&#xff0c;但是随便放入的PHP文件是不能够编译织梦 dedecms的标签的&#xff0c;所以我们需要引入织梦标签的编译引擎方案。例如&#xff0c;我们在根目录创建 example.php&#xff0c;代码如下&#xff1a;<?php …

mybatisplus代码生成器_想做时间管理大师?你可以试试Mybatis Plus代码生成器

1. 前言对于写Crud的老司机来说时间非常宝贵&#xff0c;一些样板代码写不但费时费力&#xff0c;而且枯燥无味。经常有小伙伴问我&#xff0c;胖哥你怎么天天那么有时间去搞新东西&#xff0c;透露一下秘诀呗。好吧&#xff0c;今天就把Mybatis-plus的代码生成器分享出来&…

安装Oracle 11g RAC R2 之Linux DNS 配置

Oracle 11g RAC 集群中引入了SCAN(Single Client Access Name)的概念&#xff0c;也就是指集群的单客户端访问名称。SCAN 这个特性为客户端提供了单一的主机名&#xff0c;用于访问集群中运行的 Oracle 数据库。如果您在集群中添加或删除节点&#xff0c;使用 SCAN 的客户端无需…

c++ websocket客户端_websocket使用

websocket使用一、介绍在项目开发过程中&#xff0c;很多时候&#xff0c;我们不可避免的需要实现的一个功能&#xff1a; 服务端实时发送信息给客户端。比如实时公告、实时订单通知、实时报警推送等等&#xff0c;登录后的客户端需要知道与它相关的实时信息&#xff0c;以便进…

汉子编码比字母编码长_字母/博客作者编码问题(使用动态编程)

汉子编码比字母编码长Problem statement: 问题陈述&#xff1a; Shivang is a blog writer and he is working on two websites simultaneously. He has to write two types of blogs which are: Shivang是一位博客作家&#xff0c;他同时在两个网站上工作。 他必须写两种类型…

php parent报错,mac brew 安装php扩展报错:parent directory is world writable but not sticky

$ brew install php70-mcrypt报错&#xff1a;Error: parent directory is world writable but not sticky搜索到github的答案https://github.com/Homebrew/legacy-homebrew/issues/40345原因&#xff1a;/tmp目录权限不对$ ls -ld /private/tmp打印出来 /private/tmp 被标黄了…

在cordova中使用HTML5的多文件上传

2019独角兽企业重金招聘Python工程师标准>>> 我们先看看linkface给开放的接口&#xff1a; 字段类型必需描述api_idstring是API 账户api_secretstring是API 密钥selfie_filefile见下方注释需上传的图片文件 1&#xff0c;上传本地图片进行检测时选取此参数selfie_ur…

python dataframe切片_python pandas dataframe 行列选择,切片操作方法

SQL中的select是根据列的名称来选取&#xff1b;Pandas则更为灵活&#xff0c;不但可根据列名称选取&#xff0c;还可以根据列所在的position&#xff08;数字&#xff0c;在第几行第几列&#xff0c;注意pandas行列的position是从0开始&#xff09;选取。相关函数如下&#xf…

php根据设备判断访问,PHP判断设备访问来源

/*** 判断用户请求设备是否是移动设备* return bool*/function isMobile() {//如果有HTTP_X_WAP_PROFILE则一定是移动设备if (isset($_SERVER[HTTP_X_WAP_PROFILE])) {return true;}//如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息if (isset($_SERVER[HTTP_VIA])…

机器学习 深度学习 ai_如何学习机器学习和人工智能?

机器学习 深度学习 aiSTRATEGY 战略 Learn theory practical aspects. 学习理论和实践方面的知识。 (At first get an overview of what you are going to learn). (首先获得要学习的内容的概述)。 Gain a good hold/insight on each concept. 掌握/理解每个概念。 If you …

linux常用命令和配置

2019独角兽企业重金招聘Python工程师标准>>> 启动php&#xff1a; /etc/init.d/php-fpm restart 查看PHP运行目录&#xff1a; which php /usr/bin/php 查看php-fpm进程数&#xff1a; ps aux | grep -c php-fpm 查看运行内存 /usr/bin/php -i|grep mem iptables如…

centos7时间同步_centos 8.x系统配置chrony时间同步服务

centos 8.x系统配置chrony时间同步服务CentOS 7.x默认使用的时间同步服务为ntp服务&#xff0c;但是CentOS 8开始在官方的仓库中移除了ntp软件&#xff0c;换成默认的chrony进行时间同步的服务&#xff0c;chrony既可以作为客户端向其他时间服务器发送时间同步请求&#xff0c;…

php可以用scanf,C/C++中 使用scanf和printf如何读入输出double型数据。

黄舟2017-04-17 13:47:232楼注意scanf函数和printf函数是不同寻常的函数&#xff0c;因为它们都没有将函数的参数限制为固定数量。scanf函数和printf函数又可变长度的参数列表。当调用带可变长度参数列表的函数时&#xff0c;编译器会安排float参数自动转换成为double类型&…

ICWAI和ICWA的完整形式是什么?

ICWAI / ICWA&#xff1a;印度成本与工程会计师协会/印度儿童福利法 (ICWAI / ICWA: Institute of Cost and Works Accountants of India / Indian Child Welfare Act) 1)ICWAI&#xff1a;印度成本与工程会计师协会 (1) ICWAI: Institute of Cost and Works Accountants of In…

深入研究java.lang.Runtime类【转】

转自&#xff1a;http://blog.csdn.net/lastsweetop/article/details/3961911 目录(?)[-] javalang 类 RuntimegetRuntimeexitaddShutdownHookremoveShutdownHookhaltrunFinalizersOnExitexecexecexecexecexecexecavailableProcessorsfreeMemorytotalMemorymaxMemorygcrunFina…