文件I/O实践(3) --文件共享与fcntl

简介: 文件共享 一个进程打开了两个文件文件表条目(file-table-entry):   1.

文件共享


一个进程打开了两个文件

文件表条目(file-table-entry):

   1.文件状态标志(file-status-flags): 读/写/追加/同步/非阻塞等;

   2.当前文件偏移量

   3.v节点指针


//验证
int main(int argc, char *argv[])
{
    int fd1 = open("test.txt", O_RDONLY);
    if (fd1 == -1)
        err_exit("fd1 open O_RDONLY error");
    int fd2 = open("test.txt", O_RDWR);
    if (fd2 == -1)
        err_exit("fd2 open O_RDWR error");

    //读取fd1
    char buf[BUFSIZ];
    if (read(fd1, buf, 10) == -1)
        err_exit("read fd1 error");
    cout << "fd1: " << buf << endl;

    //读取fd2
    bzero(buf, 10);
    if (read(fd2, buf, 10) == -1)
        err_exit("read fd1 error");
    cout << "fd2: " << buf << endl;

    lseek(fd1, 0, SEEK_SET);
    lseek(fd2, 0, SEEK_SET);
    write(fd2, "Helloworld", 10);
    bzero(buf, 10);
    if (read(fd1, buf, 10) == -1)
        err_exit("read fd1 error");
    cout << "after fd2 write: " << buf << endl;
}


两个独立的进程打开同一个文件

复制文件描述符

 

方法有三种:

1.dup

2.dup2 

#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);
//示例
int main(int argc, char *argv[])
{
    int fd = open("text.txt", O_WRONLY|O_TRUNC);
    if (fd == -1)
        err_exit("open O_WRONLY error");

//    close(1);   //将标准输出关闭, 则文件描述符1将空闲
//    int dupfd = dup(fd);
    int dupfd = dup2(fd, 1);
    cout << "dupfd = " << dupfd << endl;
}
/** 示例: 实现文件拷贝
其中execlp会在后面介绍
**/
int main(int argc, char *argv[])
{
    if (argc < 3)
        err_quit("usage: ./main file-name1 file-name2");

    close(STDIN_FILENO);
    open(argv[1], O_RDONLY);
    close(STDOUT_FILENO);
    open(argv[2], O_WRONLY|O_CREAT, 0666);

    execlp("/bin/cat", "cat", NULL);
    err_exit("execlp error");
}
3.fcntl
int fcntl(int fd, F_DUPFD, ... /* arg */ );
//示例见下

fcntl

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );

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

fcntl常用操作(cmd常用取值)

F_DUPFD (long)

复制文件描述符

 

F_GETFD (void)

F_SETFD (long)

文件描述符标志

 

F_GETFL (void)

F_SETFL (long)

文件状态标志

 

F_GETLK

F_SETLK,F_SETLKW(阻塞)

文件锁

//示例: 复制文件描述符
int main(int argc, char *argv[])
{
    int fd = open("text.txt", O_WRONLY|O_TRUNC);
    if (fd == -1)
        err_exit("open O_WRONLY error");

    close(1);   //将标准输出关闭, 则文件描述符1将空闲
    // 当cmd使用F_DUPFD时, 第三个参数代表搜索的起始位置
    int dupfd = fcntl(fd, F_DUPFD, 1);  // 1代表: 从1开始搜索一个空闲的文件描述符
    if (dupfd < 0)
        err_exit("fcntl F_DUPFD error");
    cout << "dupfd = " << dupfd << endl;
}

文件状态标志

F_GETFL (void)

 Get the file access mode and the file status flags; arg is ignored.

F_SETFL (int)

 Set the file status flags to  the  value  specified  by  arg.   File  access  mode(O_RDONLY,  O_WRONLY,  O_RDWR)  and  file  creation  flags (i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are ignored.  On Linux this command can change only  the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags.

//示例: 给文件描述符0设置成非阻塞模式
int main(int argc, char *argv[])
{
    int flags = fcntl(0, F_GETFL, 0);
    if (flags == -1)
        err_exit("fcntl get error");
    flags |= O_NONBLOCK;
    if (fcntl(0, F_SETFL, flags) == -1)
        err_exit("fcntl set error");

    char buf[BUFSIZ];
    if (read(0, buf, sizeof(buf)) == -1)
        err_exit("read STDIN_FILENO error");
    cout << "buffer size = " << strlen(buf) << endl;
    cout << buf << endl;
}
//示例: 文件状态设置与清除(函数封装)
void set_fl(int fd, int setFlag)
{
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1)
        err_exit("fcntl get flags error");
    //设置状态
    flags |= setFlag;
    if (fcntl(fd, F_SETFL, flags) == -1)
        err_exit("fcntl set flags error");
}
void clr_fl(int fd, int clrFlag)
{
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1)
        err_exit("fcntl get flags error");
    //清除状态
    flags &= ~clrFlag;
    if (fcntl(fd, F_SETFL, flags) == -1)
        err_exit("fcntl set flags error");
}

//测试
int main(int argc, char *argv[])
{
    set_fl(0, O_NONBLOCK);
    clr_fl(0, O_NONBLOCK);
    char buf[BUFSIZ];
    if (read(0, buf, sizeof(buf)) == -1)
        err_exit("read STDIN_FILENO error");
    cout << "buffer size = " << strlen(buf) << endl;
    cout << buf << endl;
}

文件锁

F_SETLK (struct flock *)

 Acquire  a lock (when l_type is F_RDLCK or F_WRLCK) or release a lock (when l_type is F_UNLCK) on the bytes specified by the l_whence, l_start, and l_len  fields  of lock.   If a conflicting lock is held by another process, this call returns -1 and sets errno to EACCES or EAGAIN.

F_SETLKW (struct flock *) 如果加锁不成功:会一直阻塞直到解锁

 As for F_SETLK, but if a conflicting lock is held on the file, then wait for  that lock to be released.  If a signal is caught while waiting, then the call is interrupted and (after the signal  handler  has  returned)  returns  immediately  (with return value -1 and errno set to EINTR; see signal(7)).

F_GETLK (struct flock *)

 On  input  to this call, lock describes a lock we would like to place on the file.

 If the lock could be placed, fcntl() does  not  actually  place  it,  but  returns F_UNLCK  in  the l_type field of lock and leaves the other fields of the structure unchanged.  If one or more  incompatible  locks  would  prevent  this  lock  being placed,  then  fcntl()  returns  details  about  one of these locks in the l_type, l_whence, l_start, and l_len fields of lock and sets l_pid to be the  PID  of  the process holding that lock.

//文件锁结构体
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) */
    ...
};

注意: Specifying 0 for l_len has the special meaning: lock all bytes starting  at  

the  location  specified  by l_whence and l_start through to the end of file, 

no matter how large the file grows.

//示例1
int main(int argc, char *argv[])
{
    int fd = open("test.txt", O_RDWR|O_CREAT|O_TRUNC, 0666);
    if (fd == -1)
        err_exit("open file error");

    struct flock 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)   //对比下面
    if (fcntl(fd, F_SETLKW, &lock) == 0)
    {
        cout << "file lock success, press any key to unlock..." << endl;
        cin.get();

        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = 0;
        lock.l_len = 0;
        if (fcntl(fd, F_SETLK, &lock) == -1)
            err_exit("file unlock error");
        else
            cout << "file unlock success" << endl;
    }
    else
        err_exit("file lock error");
}
//示例2: 打印加锁进程号
int main(int argc, char *argv[])
{
    int fd = open("test.txt", O_RDWR|O_CREAT|O_TRUNC, 0666);
    if (fd == -1)
        err_exit("open file error");

    struct flock 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)
    {
        cout << "file lock success, press any key to unlock..." << endl;
        cin.get();

        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = 0;
        lock.l_len = 0;
        if (fcntl(fd, F_SETLK, &lock) == -1)
            err_exit("file unlock error");
        else
            cout << "file unlock success" << endl;
    }
    else    //如果失败, 则获取锁信息
    {
        if (fcntl(fd, F_GETLK, &lock) == -1)
            err_exit("get lock error");

        cout << "lock process: " << lock.l_pid << endl;
        if (lock.l_type == F_WRLCK)
            cout << "type: F_WRLCK" << endl;
        else
            cout << "type: F_RDLCK" << endl;

        if (lock.l_whence == SEEK_SET)
            cout << "whence: SEEK_SET" << endl;
        else if (lock.l_whence == SEEK_END)
            cout << "whence: SEEK_END" << endl;
        else
            cout << "whence: SEEK_CUR" << endl;
    }
}

目录
相关文章
|
Kubernetes 网络协议 Linux
Softether VPN 打通 Kubernetes 调试网络
通过 Softether VPN 打通 Kubernetes 调试网络,其中包括无拆分隧道限制的版本,可以自定义推送路由
2486 2
|
编解码 数据安全/隐私保护
平面设计师资格证怎么考
平面设计(graphic design),也称为视觉传达设计,是以“视觉”作为沟通和表现的方式,透过多种方式来创造和结合符号、图片和文字,借此作出用来传达想法或讯息的视觉表现。
平面设计师资格证怎么考
|
存储 编解码 缓存
鹿班 PICASSO 实时渲染引擎的奥秘,如何支撑每秒千万图像访问?
读者受益: 1、鹿班PICASSO实时合图引擎因何而生 2、实时合图引擎如何支撑每秒千万图像访问 3、实时合图引擎应用场景介绍
1619 0
鹿班 PICASSO 实时渲染引擎的奥秘,如何支撑每秒千万图像访问?
|
存储 移动开发 Java
SpringBoot 接口数据加解密实战!
SpringBoot 接口数据加解密实战!
SpringBoot 接口数据加解密实战!
|
JavaScript 前端开发
『快速入门electron』之实现窗口拖拽
## 看完本文你可学会 - 对于进程通信有基本的一个了解 - 学会自定义的顶部栏如何实现拖拽功能
|
Go 开发工具 C#
产品百科 |零门槛玩转 RTC Unity Demo
本章节为您介绍了 Unity Demo 的集成操作步骤。
产品百科 |零门槛玩转 RTC Unity Demo
|
SQL NoSQL 关系型数据库
数据库领域 TOP10 热门课程推荐【第2期】 | 最棒的课程给最好的你
阿里云开发者学堂出品了近千门课程,在数据库领域中哪几门课程最受开发者们的青睐呢?小助手来揭秘!
|
传感器
一加8T发售,国行售价3399元起,骁龙865+120Hz高刷
一加8T发售,国行售价3399元起,骁龙865+120Hz高刷
783 0
一加8T发售,国行售价3399元起,骁龙865+120Hz高刷
|
新零售 小程序 机器人
解决方案应用实例 |泡泡玛特x阿里云,寻求中国潮玩领域的新突破
通过阿里云数据中台,泡泡玛特一方面实现了降本提效,提高了营销的精准性和效率,另一方面实现了数字化推动业务创新和增长,运用数据挖掘潜在用户,并和天猫合作进行新品开发。
3390 0
解决方案应用实例 |泡泡玛特x阿里云,寻求中国潮玩领域的新突破
|
机器学习/深度学习 算法 数据可视化
「直播回顾」Mars应用与最佳实践
本文首先对Mars的概念、功能、优势进行了介绍,随后,对Mars几个典型的应用场景进行介绍,并通过两个Demo展示了在使用Mars后数据科学性能的提升,最后总结了Mars的最佳实践,让使用Mars更高效便捷。
7084 0
「直播回顾」Mars应用与最佳实践