uc笔记05---sync/fsync/fdatasync,fcntl,文件锁,stat/fstat/lstat

1.    sync/fsync/fdatasync

    1)大多数磁盘 I/O 都通过缓冲进行,写入文件其实只是写入缓冲区,
      直到缓冲区满,才将其排入写队列。

    2)延迟写降低了写操作的次数,提高了写操作的效率,
      但可能导致磁盘文件与缓冲区数据不同步。

    3)sync/fsync/fdatasync 用于强制磁盘文件与缓冲区同步。

    4)sync 将所有被修改过的缓冲区排入写队列即返回,不等待写磁盘操作完成。

    5)fsync 只针对一个文件,且直到写磁盘操作完成才返回。

    6)fdatasync 只同步文件数据,不同步文件属性。

    #include <unistd.h>
    void sync (void);
    int fsync (int fd);
    成功返回 0,失败返回 -1。

    int fdatasync (int fd);
    成功返回 0,失败返回 -1。

                  +-fwrite-> 标准库缓冲 -fflush---+             sync
    应用程序内存 -+                                   +-> 内核缓冲 -fdatasync-> 磁盘(缓冲)
                  +------------write------------+             fsync

2.    fcntl
    #include <fcntl.h>
    int fcntl (
        int fd,  // 文件描述符
        int cmd, // 操作指令
        ...      // 可变参数,因操作指令而异
    );
    对 fd 文件执行 cmd 操作,某些操作需要提供参数。

    1)常用形式
    #include <fcntl.h>
    int fcntl (int fd, int cmd);
    int fcntl (int fd, int cmd, long arg);
    成功返回值因 cmd 而异,失败返回 -1。

    cmd 取值:
        F_DUPFD  - 复制 fd 为不小于 arg 的文件描述符。
                    若 arg 文件描述符已用,该函数会选择比 arg 大的最小未用值,
                    而非如 dup2 函数那样关闭之。

        F_GETFD  - 获取文件描述符标志。
                    目前仅定义了一个文件描述符标志位 FD_CLOEXEC;
                    
                    0 - 在通过 execve() 函数所创建的进程中,该文件描述符依然保持打开。
                    1 - 在通过 execve() 函数所创建的进程中,该文件描述符将被关闭。
            
        F_SETFD  - 设置文件描述符标志。
                    arg 只能取 FD_CLOEXEC (调用 exec 族函数后关闭该 fd)。

        F_GETFL  - 获取文件模式;不能获取 O_CREAT、O_EXCL 和 O_TRUNC。

        F_SETFL  - 追加文件模式;arg 只能取 O_APPEND 和 O_NONBLOCK。

    范例:dup.c
    #include <stdio.h>
    #include <string.h>
    #include <fcntl.h>
    int main (void) {
        int fd1 = open ("dup1.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if (fd1 == -1) {
            perror ("open");
            return -1;
        }
        printf ("fd1 = %d\n", fd1);

        int fd2 = open ("dup2.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if (fd2 == -1) {
            perror ("open");
            return -1;
        }
        printf ("fd2 = %d\n", fd2);
        /* fd1 复制给 fd2,若 fd2 已经打开,则关闭,返回 fd2
        int fd3 = dup2 (fd1, fd2);                    // fd1, fd2, fd3 分别为:3,4,4(对应同一个文件表)
        if (fd3 == -1) {
            perror ("dup2");
            return -1;
        }
        */
        // fd1 复制给 fd2,由于 fd2 已经打开,所以选择一个新的:
        int fd3 = fcntl (fd1, F_DUPFD, fd2);        // fd1, fd2, fd3 分别为:3,4,5(3 和 5 对应同一个文件表)
        if (fd3 == -1) {
            perror ("fcntl");
            return -1;
        }        
        printf ("fd3 = %d\n", fd3);
        
        const char* text = "123";
        if (write (fd1, text, strlen (text) * sizeof (text[0])) == -1) {
            perror ("write");
            return -1;
        }
        text = "456";
        if (write (fd2, text, strlen (text) * sizeof (text[0])) == -1) {
            perror ("write");
            return -1;
        }
        text = "789";
        if (write (fd3, text, strlen (text) * sizeof (text[0])) == -1) {
            perror ("write");
            return -1;
        }
        close (fd3);
        close (fd2);
        close (fd1);
        return 0;
    }
    分析:
        int fd3 = dup2 (fd1, fd2); fd2 复制给 fd1,如果 fd2 已经打开,则先关闭 fd2,
        然后再进行复制,那么 fd2 和 fd3 的文件描述符一样;且 fd1 fd2 fd3 三个文件的内容一样;
        上例中,fd1 fd2 fd3 内容都为:123456789
    
        int fd3 = fcntl (fd1, F_DUPFD, fd2); 同样把 fd2 复制给 fd1,如果发现 fd2 打开,
        则另外再找一个最小文件描述符给 fd3,所以 fd1 fd2 fd3 文件描述符分别为:3 4 5;
        同时,fd1 和 fd3 的内容一样,为:123789,fd2 内容为:456;

    范例:flags.c
    #include <stdio.h>
    #include <fcntl.h>
    void pflags (int flags) {
        printf ("文件模式(%08X):", flags);        // %08x 十六进制
        struct {
            int flag;
            const char* desc;
        }    flist[] = {
            O_RDONLY,   "O_RDONLY",
            O_WRONLY,   "O_WRONLY",
            O_RDWR,     "O_RDWR",
            O_APPEND,   "O_APPEND",
            O_CREAT,    "O_CREAT",
            O_EXCL,     "O_EXCL",
            O_TRUNC,    "O_TRUNC",
            O_NOCTTY,   "O_NOCTTY",
            O_NONBLOCK, "O_NONBLOCK",
            O_SYNC,     "O_SYNC",
            O_DSYNC,    "O_DSYNC",
            O_RSYNC,    "O_RSYNC",
            O_ASYNC,    "O_ASYNC"
        };
        size_t i;
        int first = 1;
        for (i = 0; i < sizeof (flist) / sizeof (flist[0]); i++)
            if (flags & flist[i].flag) {
                printf ("%s%s", first ? "" : " | ", flist[i].desc);    // 输出类似格式:O_WRONLY | O_ASYNC
                first = 0;
            }
        printf ("\n");
    }
    int main (void) {
        int fd = open ("flags.txt", O_WRONLY | O_CREAT | O_ASYNC, 0644);    // 没有即创建且异步
        if (fd == -1) {
            perror ("open");
            return -1;
        }
        int flags = fcntl (fd, F_GETFL);
        if (flags == -1) {
            perror ("fcntl");
            return -1;
        }
        pflags (flags); // O_CREATE/O_EXCL/O_TRUNC 不能被 F_GETFL 获取
        
        if (fcntl (fd, F_SETFL, O_RDWR | O_APPEND | O_NONBLOCK) == -1) {
            perror ("fcntl");
            return -1;
        }
        if ((flags = fcntl (fd, F_GETFL)) == -1) {
            perror ("fcntl");
            return -1;
        }    
        pflags (flags); // 只有 O_APPEND/O_NONBLOCK 可以被 F_SETFL 追加
        close (fd);
        return 0;
    }

    
3.    文件锁
    #include <fcntl.h>
    int fcntl (int fd, int cmd, struct flock* lock);
    其中:
    struct flock {
        short int l_type;   // 锁的类型:F_RDLCK/F_WRLCK/F_UNLCK (读锁/写锁/解锁)
        short int l_whence; // 偏移起点:SEEK_SET/SEEK_CUR/SEEK_END (文件头/当前位置/文件尾)
        off_t     l_start;  // 锁区偏移,从 l_whence 开始
        off_t     l_len;    // 锁区长度,0 表示锁到文件尾
        pid_t     l_pid;    // 加锁进程,-1 表示自动设置
    };

    cmd取值:
        F_GETLK  - 测试 lock 所表示的锁是否可加。
                    若可加则将 lock.l_type 置为 F_UNLCK,
                    否则通过 lock 返回当前锁的信息。
                    
        F_SETLK  - 设置锁定状态为 lock.l_type,(非阻塞模式)
                     成功返回 0,失败返回 -1。
                    若因其它进程持有锁而导致失败,则 errno 为 EACCES 或 EAGAIN。
                    
        F_SETLKW - 设置锁定状态为 lock.l_type,(阻塞模式:等待)
                 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值