IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> linux / fcntl 函数详解 -> 正文阅读

[系统运维]linux / fcntl 函数详解

零、作用

fcntl() 针对(文件)描述符提供控制。

  1. 复制一个现有的描述符(cmd = F_DUPFD)。?
  2. 获得/设置文件描述符标记(cmd = F_GETFDF_SETFD)。?
  3. 获得/设置文件状态标记(cmd = F_GETFLF_SETFL)。?
  4. 获得/设置异步I/O所有权(cmd = F_GETOWNF_SETOWN)。
  5. 获得/设置记录锁(cmd = F_GETLKF_SETLKF_SETLKW)。

一、原型

#include <unistd.h>
#include <fcntl.h> 
int fcntl(int fd, int cmd); 
int fcntl(int fd, int cmd, long arg); 
int fcntl(int fd, int cmd, struct flock *lock);

参数 fd 是被参数 cmd 操作的描述符。针对 cmd 的值,fcntl 能够接受第三个参数 int arg。

返回值与命令有关。如果出错,所有命令都返回-1,如果成功则返回某个其他值。下列三个命令有特定返回值:F_DUPFD、F_GETFD、F_GETFL 以及 F_GETOWN。
F_DUPFD????????返回新的文件描述符
F_GETFD????????返回相应标志
F_GETFL、F_GETOWN????????返回一个正的进程 ID 或负的进程组 ID 。

二、命令说明

1、cmd 值的 F_DUPFD

F_DUPFD:返回一个如下描述的(文件)描述符:

  • 最小的大于或等于arg的一个可用的描述符。
  • 与原始操作符一样的某对象的引用。
  • 如果对象是文件(file)的话,则返回一个新的描述符,这个描述符与 arg 共享相同的偏移量(offset)。
  • 相同的访问模式(读,写或读 / 写)。
  • 相同的文件状态标志(如:两个文件描述符共享相同的状态标志)。
  • 与新的文件描述符结合在一起的 close-on-exec 标志被设置成交叉式访问 execve(2) 的系统调用。

实际上调用 dup(oldfd),等效于

fcntl(oldfd, F_DUPFD, 0);

而调用 dup2(oldfd, newfd),等效于

close(oldfd);
fcntl(oldfd, F_DUPFD, newfd);

2、cmd 值的 F_GETLK、F_SETLK 或 F_SETLKW

(1)F_GETLK

从内核获取文件锁的信息,将其保存到第三个参数,此时第三个参数为 struct flock *flockptr。我们这里是要设置文件锁,而不是获取已有文件锁的信息,我们这里用不到这个宏。

(2)F_SETLK

设置第三个参数所代表的文件锁,而且设置的是非阻塞文件锁,也就是如果加锁失败不会阻塞。也就是说加锁失败后如果不想阻塞的话,就是由 F_SETLK 宏来决定的。

此时需要用到第三个参数,struct flock *flockptr。

使用举例:

第一步:定义一个 struct flock flockptr 结构体变量(这个结构体变量就是文件锁)。

第二步:设置 flockptr 的成员,表示你想设置什么样的文件锁。

第三步:通过第三个参数,将设置好的 flockptr 的地址传递给 fcntl,设置你要的文件锁

(3)F_SETLKW

与 F_SETLK 一样,只不过设置的是阻塞文件锁,也就说加锁不成功的话就阻塞,是由F_SETLKW宏来决定的。

第三个参数

第三个参数设置为什么视情况而定,如果 fcntl 用于实现文件锁的话,第三个参数为 struct flock *flockptr,flockptr 代表的就是文件锁。对 flockptr 的成员设置为特定的值,就可以将文件锁设置为你想要的锁。

struct flock结构体如下:

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_type:锁类型

  • F_RDLCK:读锁(或称共享锁)
  • F_WRLCK:写锁
  • F_UNLCK:解锁?

l_whence:加锁位置粗定位,设置同 lseek 的 whence

  • SEEK_SET:文件开始处
  • SEEK_CUR:文件当前位置处
  • SEEK_END:文件末尾位置处

l_whence 这个与 lseek 函数的 whence 是一个含义,off_t lseek(int fd, off_t offset, int whence);

l_start:精定位,相对 l_whence 的偏移,与 lseek 的 offset 的含义完全一致

通过 l_whence 和 l_start 的值,就可以用来指定从文件的什么位置开始加锁,不过一般来说,我们会将 l_whence 指定为SEEK_SET,l_start 指定为 0,表示从整个文件头上开始加锁。

l_len:从 l_whence 和 l_start 所指定的起始地点算起,对文件多长的内容加锁。

如果 l_len 被设置 0,表示一直加锁到文件的末尾,如果文件长度是变化的,将自动调整加锁的末尾位置。

将 l_whence 和 l_start 设置为 SEEK_SET 和 0,然后再将 l_len 设置为 0,就表示从文件头加锁到文件末尾,其实就是对整个文件加锁。

flockptr.l_whence=SEEK_SET;                                            
flockptr.l_start=0;                                            
flockptr.l_len=0;

就就表示对整个文件加锁。

如果只是对文件中间的某段加锁,这只是区域加锁,加区域锁时可以给文件 n 多个的独立区域加锁。

l_pid:当前正加着锁的那个进程的 PID 。

只有当我们获取一个已存在锁的信息时,才会使用这个成员,这个成员的值不是我们设置的,是由文件锁自己设置的,我们只是获取以查看当前那个进程正加着锁。对于我们目前设置文件锁来说,这个成员用不到。

栗子

使用文件锁的互斥操作,解决父子进程向同一文件写“hello ”,“world\n”时,hello hello world相连的问题。

【file_lock.h】

#ifndef H_FILELOCK_H
#define H_FILELOCK_H

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

//非阻塞设置写锁
#define SET_WRFLCK(fd, l_whence, l_offset, l_len) \
    set_filelock(fd, F_SETLK, F_WRLCK, l_whence, l_offset, l_len)
//阻塞设置写锁
#define SET_WRFLCK_W(fd, l_whence, l_offset, l_len) \
    set_filelock(fd, F_SETLKW, F_WRLCK, l_whence, l_offset, l_len)

//非阻塞设置读锁
#define SET_RDFLCK(fd, l_whence, l_offset, l_len) \
    set_filelock(fd, F_SETLK, F_RDLCK, l_whence, l_offset, l_len)
//阻塞设置读锁
#define SET_RDFLCK_W(fd, l_whence, l_offset, l_len) \
    set_filelock(fd, F_SETLKW, F_RDLCK, l_whence, l_offset, l_len)

//解锁
#define UNLCK(fd, l_whence, l_offset, l_len) \
    set_filelock(fd, F_SETLK, F_UNLCK, l_whence, l_offset, l_len)

/* 调用这个函数,即可实现阻塞加读锁/阻塞加写锁, 非阻塞加读锁/非阻塞加写锁/解锁 */
static void set_filelock(int fd, int ifwait, int l_type, int l_whence,
    int l_offset, int l_len)
{
    int ret = 0;
    struct flock flck;

    flck.l_type = l_type;
    flck.l_whence = l_whence;
    flck.l_start = l_offset;
    flck.l_len = l_len;

    ret = fcntl(fd, ifwait, &flck);
    if (ret == -1) {
        perror("fcntl fail");
        exit(-1);
    }
}

#endif

【main.c】?

#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "file_lock.h"

#define PARENT_CONTENT "parent process\n"
#define SUN_CONTENT "sun process\n"

void print_err(char *str, int line, int err_no)
{
    printf("%d, %s: %s\n", line, str, strerror(err_no));
    exit(-1);
}

int main(void)
{
    int fd = 0;
    int ret = 0;

    fd = open("./file", O_RDWR | O_CREAT | O_TRUNC, 0664);
    if (fd == -1)
        print_err("./file", __LINE__, errno);

    ret = fork();
    if (ret > 0) {
        while (1) {
            SET_WRFLCK_W(fd, SEEK_SET, 0, 0);
            write(fd, PARENT_CONTENT, strlen(PARENT_CONTENT));
            UNLCK(fd, SEEK_SET, 0, 0);
            sleep(1);
        }
    } else if (ret == 0) {
        while (1) {
            SET_WRFLCK_W(fd, SEEK_SET, 0, 0);
            write(fd, SUN_CONTENT, strlen(SUN_CONTENT));
            UNLCK(fd, SEEK_SET, 0, 0);
            sleep(1);
        }
    }

    return 0;
}
gcc -o main main.c

?结果:

(SAW:Game Over!)?

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-05-24 18:35:01  更:2022-05-24 18:37:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 15:55:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码