第3章——《文件I/O》(2)

2018-07-14  本文已影响0人  alex_man

实验环境介绍

文件共享

unix系统支持在不同进程中共享打开文件。

内核为打开的文件维护的数据结构

linux没有使用v节点,使用的是通用的i节点结构。虽然两者实现不同,但在概念上v节点和i节点是一样的,都指向了文件系统系统特有的i节点结构。上图中就是一个例子。

可能有多个文件描述符指向同一个文件表项,讨论dup函数的时候,我们再来讨论。此外fork之后也会发生同样的情况,此时父进程和紫禁城各自的每一个文件描述符共享对应的同一个文件表项(第八章来讨论)。注意:文件描述符标志和文件状态标志在作用范围方面是有区别的,前者只用于一个进程的一个文件描述符,而后者则应用于指向该给定文件表项的任何进程中的所有描述符。后面讨论fcntl函数的时候再来讨论如何获取文件描述符标志和文件状态标志。

原子操作

原子操作指的是由多步组成的一个操作。防止多个操作之间被别的操作打断而导致数据不同步,从而导致多个操作的结果没有达到预期
多进程读写以及pread和pwrite函数

single unix specification包括了xsi扩展,该扩展允许原子性地定位并执行I/O

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

#define bool unsigned char
#define true 1
#define false 0

#ifdef TEST
#define READ(fd, buf_p, count, offset) pread(fd, buf_p, count, offset) 
#else
#define READ(fd, buf_p, count, offset) read(fd, buf_p, count) 
#endif

#define READ_TIME 10

#define FILE_PATH "/home/manjingliu/apue/part_3/tmp"

bool
create_thread(void *(*fun)(void *_arg), void *arg);

void *
pread_test(void *arg);

int
main(int argc, char *argv[])
{
    system("touch /home/manjingliu/apue/part_3/tmp;echo 1234567890 > \
        /home/manjingliu/apue/part_3/tmp");

    int fd = open(FILE_PATH, O_RDONLY);
    if (fd < 0) {
        printf("opne %s error\n", FILE_PATH);
    }

    create_thread(pread_test, &fd);
    create_thread(pread_test, &fd);

    while (1)
        sleep(1);

    exit(EXIT_SUCCESS);
}

bool
create_thread(void *(*fun)(void *_arg), void *arg)
{
    pthread_t tid;
    int err = pthread_create(&tid, NULL, fun, arg);
    if (err) {
        printf("create thread error\n");
        return false;
    }
    printf("create thread %ld successfully\n", tid);

    if (pthread_detach(tid)) {
        printf("detach thread %ld error(%s)\n", tid, strerror(errno));
        return false;
    }
    printf("detach thread %ld successfully\n", tid);

    return true;
}

void *
pread_test(void *fd)
{
    printf("tid: %ld\n", pthread_self());

    char buf[10] = {0};
    int i = 0;
    while (i < READ_TIME) {
        if (READ(*((int *)fd), &buf[i], 1, i) <= 0)
            printf("tid: %ld read error(%s)\n", pthread_self(), strerror(errno));
        i++;
        sleep(1);
    }

    i = 0;
    while (i < READ_TIME)
        printf("%c\n", buf[i++]);
    
    printf("tid: %ld exit\n", pthread_self());
    return ((void *)0);
}

read版本
result:
[manjingliu@localhost part_3]$ gcc -Wall 3_11.c -o 3_11 -std=c99 -lpthread 
[manjingliu@localhost part_3]$ 
[manjingliu@localhost part_3]$ ./3_11
create thread 139985312143104 successfully
detach thread 139985312143104 successfully
create thread 139985303750400 successfully
detach thread 139985303750400 successfully
tid: 139985303750400
tid: 139985312143104
tid: 139985312143104 read error(Success)
tid: 139985303750400 read error(Success)
tid: 139985312143104 read error(Success)
tid: 139985312143104 read error(Success)
tid: 139985303750400 read error(Success)
tid: 139985312143104 read error(Success)
tid: 139985303750400 read error(Success)
tid: 139985303750400 read error(Success)
tid: 139985312143104 read error(Success)
2
4
6
8
0





tid: 139985312143104 exit
1
3
5
7
9






tid: 139985303750400 exit

pread版本
result:
[manjingliu@localhost part_3]$ gcc -Wall 3_11.c -o 3_11 -std=c99 -lpthread -DTEST
3_11.c: In function ‘pread_test’:
3_11.c:79:3: warning: implicit declaration of function ‘pread’ [-Wimplicit-function-declaration]
  if (READ(*((int *)fd), &buf[i], 1, i) <= 0)
  ^
[manjingliu@localhost part_3]$ ./3_11
create thread 139777443800832 successfully
detach thread 139777443800832 successfully
tid: 139777443800832
create thread 139777435408128 successfully
detach thread 139777435408128 successfully
tid: 139777435408128
1
2
3
4
5
6
7
8
9
0
tid: 139777443800832 exit
1
2
3
4
5
6
7
8
9
0
tid: 139777435408128 exit

dup和dup2函数

[图片上传失败...(image-4fec68-1531646493559)]

功能:这两个函数用于复制一个现有的文件描述符

但是注意: 这两个描述符不共享文件描述符标志(close-on-exec标志)。close-on-exec标志(FD_CLOEXEC;对于重复描述符,请参阅fcntl(2)。

O_CLOEXEC模式和FD_CLOEXEC选项
O_CLOEXEC模式和FD_CLOEXEC选项的代码测试(包括fork、单进程、dup的情景)
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define FILENAME "O_CLOEXEC.tmp"

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)


int main()
{
    int fd, fd2, val;
    pid_t pid;

#ifdef _O_CLOEXEC
    if ((fd = open(FILENAME, O_RDWR | O_CREAT | O_CLOEXEC, 0600)) < 0) 
#else
    if ((fd = open(FILENAME, O_RDWR | O_CREAT, 0600)) < 0) 
#endif
        err_sys("open error");

#ifdef _DUP
    if ((fd2 = dup(fd)) < 0)
        err_sys("dup error");
    if (write(fd2, "123", 3) < 0)
        err_sys("write error");

    if ((val = fcntl(fd, F_GETFD)) < 0)
        err_sys("fcntl(F_GETFD) error");
    else
        printf("O_CLOEXEC is %s set\n", (val & FD_CLOEXEC) ? "" : "not");

    if ((val = fcntl(fd2, F_GETFD)) < 0)
        err_sys("fcntl(F_GETFD) error");
    else
        printf("O_CLOEXEC is %s set in dup\n", (val & FD_CLOEXEC) ? "" : "not");
#endif

#ifdef _FCNTL_CLOEXEC
    if ((val = fcntl(fd, F_GETFD)) < 0)
        err_sys("fcntl(F_GETFD) error");

    val |= FD_CLOEXEC;
    if (fcntl(fd, F_SETFD, val) < 0)
        err_sys("fcntl( F_SETFD) error");
#endif

#ifndef _FORK 
    if (execl("/usr/bin/sleep", "sleep", "10000", (void*)0) < 0)
        err_sys("execl error");
#else
switch ((pid = fork())) {
        case -1:
            err_sys("fork error");
        case 0:
            sleep(10000);
            break;
        default:
            sleep(10000);
            break;
    }
#endif

    exit(EXIT_SUCCESS);
}
/* 1.1单进程设置O_CLOEXEC,execl执行命令 */
[manjingliu@localhost part_3]$ gcc -D_O_CLOEXEC -o cloexec 3_12.c 
[manjingliu@localhost part_3]$ ./cloexec 

[manjingliu@localhost root]$ ps -ef | grep -v grep | grep sleep
manjing+  63509  59279  0 11:47 pts/3    00:00:00 sleep 10000
[manjingliu@localhost root]$ lsof -p 63509
COMMAND  PID      USER  FD  TYPE DEVICE  SIZE/OFF    NODE NAME
sleep  63509 manjingliu  cwd    DIR  253,0      117  1164545 /home/manjingliu/apue/part_3
sleep  63509 manjingliu  rtd    DIR  253,0      244      64 /
sleep  63509 manjingliu  txt    REG  253,0    33112 50381418 /usr/bin/sleep
sleep  63509 manjingliu  mem    REG  253,0 106070960 16997546 /usr/lib/locale/locale-archive
sleep  63509 manjingliu  mem    REG  253,0  2173512    42306 /usr/lib64/libc-2.17.so
sleep  63509 manjingliu  mem    REG  253,0    164240    32424 /usr/lib64/ld-2.17.so
sleep  63509 manjingliu    0u  CHR  136,3      0t0        6 /dev/pts/3
sleep  63509 manjingliu    1u  CHR  136,3      0t0        6 /dev/pts/3
sleep  63509 manjingliu    2u  CHR  136,3      0t0        6 /dev/pts/3

此时,sleep进程没有占用O_CLOEXEC.tmp文件

/* 1.2单进程无设置O_CLOEXEC,execl执行命令 */
[manjingliu@localhost part_3]$ gcc -o nocloexec 3_12.c 
[manjingliu@localhost part_3]$ ./nocloexec 

[manjingliu@localhost root]$ ps -ef | grep -v grep | grep sleep
manjing+  63565  59279  0 11:55 pts/3    00:00:00 sleep 10000
[manjingliu@localhost root]$ lsof -p 63565
COMMAND  PID      USER  FD  TYPE DEVICE  SIZE/OFF    NODE NAME
sleep  63565 manjingliu  cwd    DIR  253,0      134  1164545 /home/manjingliu/apue/part_3
sleep  63565 manjingliu  rtd    DIR  253,0      244      64 /
sleep  63565 manjingliu  txt    REG  253,0    33112 50381418 /usr/bin/sleep
sleep  63565 manjingliu  mem    REG  253,0 106070960 16997546 /usr/lib/locale/locale-archive
sleep  63565 manjingliu  mem    REG  253,0  2173512    42306 /usr/lib64/libc-2.17.so
sleep  63565 manjingliu  mem    REG  253,0    164240    32424 /usr/lib64/ld-2.17.so
sleep  63565 manjingliu    0u  CHR  136,3      0t0        6 /dev/pts/3
sleep  63565 manjingliu    1u  CHR  136,3      0t0        6 /dev/pts/3
sleep  63565 manjingliu    2u  CHR  136,3      0t0        6 /dev/pts/3
sleep  63565 manjingliu    3u  REG  253,0        0  1164889 /home/manjingliu/apue/part_3/O_CLOEXEC.tmp

此时,sleep进程占用O_CLOEXEC.tmp文件,说明sleep进程没有关闭O_CLOEXEC.tmp文件
/* 2.1单进程设置FD_CLOEXEC,execl执行命令 */
[manjingliu@localhost part_3]$ 
[manjingliu@localhost part_3]$ gcc -o fcntl_cloexec -D_FCNTL_CLOEXEC 3_12.c 
[manjingliu@localhost part_3]$ ./fcntl_cloexec

[manjingliu@localhost root]$ ps -ef | grep -v grep | grep sleep
manjing+  63622  59279  0 12:02 pts/3    00:00:00 sleep 10000
[manjingliu@localhost root]$ lsof -p 63622
COMMAND  PID      USER  FD  TYPE DEVICE  SIZE/OFF    NODE NAME
sleep  63622 manjingliu  cwd    DIR  253,0      155  1164545 /home/manjingliu/apue/part_3
sleep  63622 manjingliu  rtd    DIR  253,0      244      64 /
sleep  63622 manjingliu  txt    REG  253,0    33112 50381418 /usr/bin/sleep
sleep  63622 manjingliu  mem    REG  253,0 106070960 16997546 /usr/lib/locale/locale-archive
sleep  63622 manjingliu  mem    REG  253,0  2173512    42306 /usr/lib64/libc-2.17.so
sleep  63622 manjingliu  mem    REG  253,0    164240    32424 /usr/lib64/ld-2.17.so
sleep  63622 manjingliu    0u  CHR  136,3      0t0        6 /dev/pts/3
sleep  63622 manjingliu    1u  CHR  136,3      0t0        6 /dev/pts/3
sleep  63622 manjingliu    2u  CHR  136,3      0t0        6 /dev/pts/3

此时,sleep进程没有占用O_CLOEXEC.tmp文件

/* 2.2单进程无设置FD_CLOEXEC,execl执行命令 */
[manjingliu@localhost root]$ ps -ef | grep -v grep | grep sleep
manjing+  63633  59279  2 12:05 pts/3    00:00:00 sleep 10000
[manjingliu@localhost root]$ lsof -p 63633
COMMAND  PID      USER  FD  TYPE DEVICE  SIZE/OFF    NODE NAME
sleep  63633 manjingliu  cwd    DIR  253,0      178  1164545 /home/manjingliu/apue/part_3
sleep  63633 manjingliu  rtd    DIR  253,0      244      64 /
sleep  63633 manjingliu  txt    REG  253,0    33112 50381418 /usr/bin/sleep
sleep  63633 manjingliu  mem    REG  253,0 106070960 16997546 /usr/lib/locale/locale-archive
sleep  63633 manjingliu  mem    REG  253,0  2173512    42306 /usr/lib64/libc-2.17.so
sleep  63633 manjingliu  mem    REG  253,0    164240    32424 /usr/lib64/ld-2.17.so
sleep  63633 manjingliu    0u  CHR  136,3      0t0        6 /dev/pts/3
sleep  63633 manjingliu    1u  CHR  136,3      0t0        6 /dev/pts/3
sleep  63633 manjingliu    2u  CHR  136,3      0t0        6 /dev/pts/3
sleep  63633 manjingliu    3u  REG  253,0        0  1164889 /home/manjingliu/apue/part_3/O_CLOEXEC.tmp
此时,sleep进程占用O_CLOEXEC.tmp文件,说明sleep进程没有关闭O_CLOEXEC.tmp文件
/* 3.1多进程设置O_CLOEXEC选项  */
[manjingliu@localhost part_3]$ gcc -o fork_cloexec -D_O_CLOEXEC -D_FORK 3_12.c 
[manjingliu@localhost part_3]$ ./fork_cloexec 

[manjingliu@localhost root]$ ps -ef | grep -v grep | grep fork
dbus        660      1  0 Jul10 ?        00:00:02 /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
manjing+  63646  59279  0 12:09 pts/3    00:00:00 ./fork_cloexec
manjing+  63647  63646  0 12:09 pts/3    00:00:00 ./fork_cloexec

[manjingliu@localhost root]$ lsof -p 63646
COMMAND    PID      USER  FD  TYPE DEVICE SIZE/OFF    NODE NAME
fork_cloe 63646 manjingliu  cwd    DIR  253,0      198 1164545 /home/manjingliu/apue/part_3
fork_cloe 63646 manjingliu  rtd    DIR  253,0      244      64 /
fork_cloe 63646 manjingliu  txt    REG  253,0    8832 1164900 /home/manjingliu/apue/part_3/fork_cloexec
fork_cloe 63646 manjingliu  mem    REG  253,0  2173512  42306 /usr/lib64/libc-2.17.so
fork_cloe 63646 manjingliu  mem    REG  253,0  164240  32424 /usr/lib64/ld-2.17.so
fork_cloe 63646 manjingliu    0u  CHR  136,3      0t0      6 /dev/pts/3
fork_cloe 63646 manjingliu    1u  CHR  136,3      0t0      6 /dev/pts/3
fork_cloe 63646 manjingliu    2u  CHR  136,3      0t0      6 /dev/pts/3
fork_cloe 63646 manjingliu    3u  REG  253,0        0 1164889 /home/manjingliu/apue/part_3/O_CLOEXEC.tmp

[manjingliu@localhost root]$ lsof -p 63647
COMMAND    PID      USER  FD  TYPE DEVICE SIZE/OFF    NODE NAME
fork_cloe 63647 manjingliu  cwd    DIR  253,0      198 1164545 /home/manjingliu/apue/part_3
fork_cloe 63647 manjingliu  rtd    DIR  253,0      244      64 /
fork_cloe 63647 manjingliu  txt    REG  253,0    8832 1164900 /home/manjingliu/apue/part_3/fork_cloexec
fork_cloe 63647 manjingliu  mem    REG  253,0  2173512  42306 /usr/lib64/libc-2.17.so
fork_cloe 63647 manjingliu  mem    REG  253,0  164240  32424 /usr/lib64/ld-2.17.so
fork_cloe 63647 manjingliu    0u  CHR  136,3      0t0      6 /dev/pts/3
fork_cloe 63647 manjingliu    1u  CHR  136,3      0t0      6 /dev/pts/3
fork_cloe 63647 manjingliu    2u  CHR  136,3      0t0      6 /dev/pts/3
fork_cloe 63647 manjingliu    3u  REG  253,0        0 1164889 /home/manjingliu/apue/part_3/O_CLOEXEC.tmp

这说明fork会让子进程继承父进程的文件描述符标志(写实复制)
/* 4.1dup对O_CLOEXEC选项的影响  */
[manjingliu@localhost part_3]$ gcc -o dup_cloexec -D_O_CLOEXEC -D_DUP 3_12.c 
[manjingliu@localhost part_3]$ ./dup_cloexec 
O_CLOEXEC is  set
O_CLOEXEC is not set in dup

说明dup清除了新文件描述符的文件描述符标志O_CLOEXEC

sync、fsync和fdatasync函数

[图片上传失败...(image-c358c8-1531646493559)]

fcntl函数

[图片上传失败...(image-ca8955-1531646493559)]

功能作用

这次只先说明下除了记录锁相关的几种

cmd操作
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define FILENAME "fcntl.tmp"

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)


int main()
{
    int fd, fd2, fd3, val;

    if ((fd = open(FILENAME, O_RDWR | O_CREAT | O_CLOEXEC, 0600)) < 0) 
        err_sys("open error");

    if ((fd2 = fcntl(fd, F_DUPFD)) < 0)
        err_sys("fcntl(F_GETFD) error");

    if ((fd3 = fcntl(fd, F_DUPFD_CLOEXEC, 1)) < 0)
        err_sys("fcntl(F_GETFD) error");

    if ((val = fcntl(fd, F_GETFD)) < 0)
        err_sys("fcntl(F_GETFD) error");
    else
        printf("O_CLOEXEC is %s set in fd\n", (val & FD_CLOEXEC) ? "" : "not");

    if ((val = fcntl(fd2, F_GETFD)) < 0)
        err_sys("fcntl(F_GETFD) error");
    else
        printf("O_CLOEXEC is %s set in F_DUPFD fd2\n", (val & FD_CLOEXEC) ? "" : "not");

    if ((val = fcntl(fd3, F_GETFD)) < 0)
        err_sys("fcntl(F_GETFD) error");
    else
        printf("O_CLOEXEC is %s set in F_DUPFD_CLOEXEC fd3\n", (val & FD_CLOEXEC) ? "" : "not");

    exit(EXIT_SUCCESS);
}

result:
[manjingliu@localhost part_3]$ ./3_14
O_CLOEXEC is  set in fd
O_CLOEXEC is not set in F_DUPFD fd2
O_CLOEXEC is  set in F_DUPFD_CLOEXEC fd3

注意:O_RDONLY、O_WRONLY、O_RDWR、O_EXEC、O_SEARCH这几个值并不是占一个bit位(ps: 在本机上没找O_EXEC、O_SEARCH这两个宏),可以用O_ACCCMODE获得某个文件的文件状态标志

总结简单测试
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define FILENAME "fcntl.tmp"

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)


int main(int argc, char *argv[])
{
    int val;

    if (argc != 2) 
        err_sys("Usage: a.out <description#>");

    if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
        err_sys("fcntl error for fd %d", atoi(argv[1]));

    switch (val & O_ACCMODE) {
    case O_RDWR:
        printf("read write");
        break;

    case O_RDONLY:
        printf("read only");
        break;

    case O_WRONLY:
        printf("write only");
        break;

    default:
        printf("unknow access mode");
    }

    if (val & O_APPEND)
        printf(", append");
    if (val & O_NONBLOCK)
        printf(", nonblocking");
    if (val & O_SYNC)
        printf(", synchronous");

#if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC) && (O_FSYNC != O_SYNC)
    if (val & O_FSYNC)
        printf(", synchronous writes");
#endif

    putchar('\n');
    exit(EXIT_SUCCESS);
}

reuslt:
[manjingliu@localhost part_3]$ ./3_15 O_CLOEXEC.tmp 
read write, append
[manjingliu@localhost part_3]$ ./3_15 < /dev/tty
Usage: a.out <description#>
errno:0 Success
[manjingliu@localhost part_3]$ ./3_15 0 < /dev/tty
read only
[manjingliu@localhost part_3]$ ./3_15 1  >  temp.foo
[manjingliu@localhost part_3]$ cat temp.foo 
write only
[manjingliu@localhost part_3]$ ./3_15 2 2>>  temp.foo
write only, append
[manjingliu@localhost part_3]$ ./3_15 5 5<>  temp.foo
read write
O_SYNC,同步写
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/times.h>

#define BYTES (1 * 516581760L) 
#define BUFF_LEN 32768

#define ORG_FILE "oo.org"
#define FILE_NAME1 "oo.1"
#define FILE_NAME2 "oo.2"
#define FILE_NAME3 "oo.3"
#define FILE_NAME4 "oo.4"
#define FILE_NAME5 "oo.5"

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)

#define err_dump(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
} while (0)

void
cal_func_time(void (*func)(void), int arg);

void
set_fl(int fd, int flags);

void 
normal_write(void);

void 
normal_o_sync_write(void);

void 
normal_fdatasync_write(void);

void 
normal_fsync_write(void);

void 
normal_o_sync_fsync_write(void);

int
main(int argc, char *argv[])
{
    cal_func_time(normal_write, 0);
    cal_func_time(normal_o_sync_write, 0);
    cal_func_time(normal_fdatasync_write, 0);
    cal_func_time(normal_fsync_write, 0);
    cal_func_time(normal_o_sync_fsync_write, 0);

    exit(EXIT_SUCCESS);
}

void
cal_func_time(void (*func)(void), int arg)
{
    int sc_clk_tck;
    sc_clk_tck = sysconf(_SC_CLK_TCK);
    struct tms begin_tms, end_tms;
    clock_t begin, end;
    begin = times(&begin_tms);

    func();
    end = times(&end_tms);
    printf("real time: %lf\n", (end - begin) / (double)sc_clk_tck);
    printf("user time: %lf\n",
            (end_tms.tms_utime - begin_tms.tms_utime) / (double)sc_clk_tck);
    printf("sys time: %lf\n",
            (end_tms.tms_stime - begin_tms.tms_stime) / (double)sc_clk_tck);
}

void
set_fl(int fd, int flags)
{
    int val;
    if ((val = fcntl(fd, F_GETFL, 0)) < 0)
        err_sys("fcntl F_GETFL error");

    val |= flags;

    if (fcntl(fd, F_SETFL, val) < 0)
        err_sys("fcntl F_SETFL error");
}

void 
normal_write(void)
{
    ssize_t n;
    char buf[BUFF_LEN];

    printf("+++++++++++write disk normally+++++++++++++\n");

    int open_fd = open(ORG_FILE, O_RDONLY);  
    if (open_fd < 0) {
        err_sys("open %s error", ORG_FILE);
    } 

    int open_fd1 = open(FILE_NAME1, O_RDWR | O_CREAT | O_TRUNC, 0666);
    if (open_fd1 < 0) {
        err_sys("open open %s error", FILE_NAME1);
    }

    long has_read = 0;
    while (1) {
        n = read(open_fd, buf, BUFF_LEN);
        if ( n < 0 ) {
            err_sys("read error");
            break;
        } else if (n == 0) {
            printf("has read over all: %ld\n", has_read);
            break;
        } 

        if (write(open_fd1, buf, n) != n) {
            printf("write error\n");
            break;
        } else 
            has_read += n;
    }
    close(open_fd);
    close(open_fd1);
}

void 
normal_o_sync_write(void)
{
    ssize_t n;
    char buf[BUFF_LEN];

    printf("+++++++++++normal_o_sync_write+++++++++++++\n");

    int open_fd = open(ORG_FILE, O_RDONLY);  
    if (open_fd < 0) {
        err_sys("open %s error", ORG_FILE);
    } 

    int open_fd1 = open(FILE_NAME2, O_RDWR | O_CREAT | O_TRUNC, 0666);
    if (open_fd1 < 0) {
        err_sys("open open %s error", FILE_NAME2);
    }
    
    set_fl(open_fd1, O_SYNC);

    long has_read = 0;
    while (1) {
        n = read(open_fd, buf, BUFF_LEN);
        if ( n < 0 ) {
            err_sys("read error");
            break;
        } else if (n == 0) {
            printf("has read over all: %ld\n", has_read);
            break;
        } 

        if (write(open_fd1, buf, n) != n) {
            printf("write error\n");
            break;
        } else 
            has_read += n;
    }
    close(open_fd);
    close(open_fd1);
}

void 
normal_fdatasync_write(void)
{
    ssize_t n;
    char buf[BUFF_LEN];

    printf("+++++++++++normal_fdatasync_write+++++++++++++\n");

    int open_fd = open(ORG_FILE, O_RDONLY);  
    if (open_fd < 0) {
        err_sys("open %s error", ORG_FILE);
    } 

    int open_fd1 = open(FILE_NAME3, O_RDWR | O_CREAT | O_TRUNC, 0666);
    if (open_fd1 < 0) {
        err_sys("open open %s error", FILE_NAME2);
    }
    
    long has_read = 0;
    while (1) {
        n = read(open_fd, buf, BUFF_LEN);
        if ( n < 0 ) {
            err_sys("read error");
            break;
        } else if (n == 0) {
            printf("has read over all: %ld\n", has_read);
            break;
        } 

        if (write(open_fd1, buf, n) != n) {
            printf("write error\n");
            break;
        } else {
            if (fdatasync(open_fd1))
                err_dump("fdatasync error");
            has_read += n;
        }
    }
    close(open_fd);
    close(open_fd1); 
}

void 
normal_fsync_write(void)
{
    ssize_t n;
    char buf[BUFF_LEN];

    printf("+++++++++++normal_fsync_write+++++++++++++\n");

    int open_fd = open(ORG_FILE, O_RDONLY);  
    if (open_fd < 0) {
        err_sys("open %s error", ORG_FILE);
    } 

    int open_fd1 = open(FILE_NAME4, O_RDWR | O_CREAT | O_TRUNC, 0666);
    if (open_fd1 < 0) {
        err_sys("open open %s error", FILE_NAME2);
    }
    

    long has_read = 0;
    while (1) {
        n = read(open_fd, buf, BUFF_LEN);
        if ( n < 0 ) {
            err_sys("read error");
            break;
        } else if (n == 0) {
            printf("has read over all: %ld\n", has_read);
            break;
        } 

        if (write(open_fd1, buf, n) != n) {
            printf("write error\n");
            break;
        } else {
            if (fsync(open_fd1))
                err_dump("fsync error");
            has_read += n;
        }
    }
    close(open_fd);
    close(open_fd1);    
}

void 
normal_o_sync_fsync_write(void)
{
    ssize_t n;
    char buf[BUFF_LEN];

    printf("+++++++++++normal_o_sync_fsync_write+++++++++++++\n");

    int open_fd = open(ORG_FILE, O_RDONLY);  
    if (open_fd < 0) {
        err_sys("open %s error", ORG_FILE);
    } 

    int open_fd1 = open(FILE_NAME5, O_RDWR | O_CREAT | O_TRUNC, 0666);
    if (open_fd1 < 0) {
        err_sys("open open %s error", FILE_NAME2);
    }
    
    set_fl(open_fd1, O_SYNC);

    long has_read = 0;
    while (1) {
        n = read(open_fd, buf, BUFF_LEN);
        if ( n < 0 ) {
            err_sys("read error");
            break;
        } else if (n == 0) {
            printf("has read over all: %ld\n", has_read);
            break;
        } 

        if (write(open_fd1, buf, n) != n) {
            printf("write error\n");
            break;
        } else {
            if (fsync(open_fd1))
                err_dump("fsync error");
            has_read += n;
        }
    }
    close(open_fd);
    close(open_fd1);    
}

ioctl函数

/dev/fd

fd = open("/dev/fd/0", mode);
等价于
fd = dup(0);
0和fd共享一份文件表项
fd = open("/dev/fd/0", O_RDWR);

在linux上这么做必须很小心,linux的实现是使用了符号链接,对其进行creat可能会导致底层文件断裂

上一篇 下一篇

猜你喜欢

热点阅读