APUE(3)---文件I/O (3)

12、函數sync、fsync和fdatasync數據庫

  延遲寫:傳統的Unix系統在內核中設有緩衝區或頁高速緩衝,大多數磁盤I/O都經過緩衝區進行,當咱們向文件寫入數據時,內核一般先將數據複製到緩衝區,而後排入隊列,晚些時候再寫入磁盤。Unix系統提供了sync、fsync和fdatasync三個函數。安全

#include <unistd.h>
int fsync(inf fd);
int fdatasync(int fd);
//若成功,返回0;若出錯,返回-1
void sync(void);

  sync只是將全部修改過的塊緩衝區排入寫隊列,而後就返回,它並不等待實際磁盤操做結束。一般稱爲update的喜歡守護進程週期性地調用sync函數,這就保證了按期沖洗(flush)內核的塊緩衝區。app

  fsync函數只對內核文件描述符fd指定的一個文件起做用,而且等待寫磁盤操做結束後才返回,其主要應用場景是數據庫內應用。異步

  fdatasync函數相似fsync,但他至響應文件的數據部分。而除數據外,fsync還會更新文件的屬性。async

十3、函數fcntl函數

#include <fcntl.h>
int fcntl(int fd, int cmd, .../*int arg*/);
//若成功,則依賴於cmd;若出錯,則返回-1

   fcntl函數能夠改變已經打開文件的屬性,有如下5個功能:ui

1.複製一個已有的描述符(cmd = F_DUPFD 或 F_DUPED_CLOEXEC)spa

2.獲取、設置文件描述符標誌(cmd = F_GETFD 或 F_SETFD)code

3.獲取、設置文件狀態標誌(cmd = F_GETFL 或 F_SETFL)blog

4.獲取、設置異步I/O全部權(cmd = F_GETOWN 或 F_SETOWN)

5.獲取、設置記錄鎖(cmd = F_GETLK、F_SETLK 或 F_SETLKM)

F_DUPFD        : 複製文件描述符fd,新文件描述符做爲函數返回值,它是還沒有打開的各描述符中大於或等於第三個參數值返回。新描述符和fd共享一張文件表項,可是新文件描述符由他本身的一套文件文件描述符標誌。其FD_CLOEXEC文件描述符標誌被清除。

F_DUPED_CLOEXEC: 複製文件描述符,設置與新描述符關聯的FD_CLOEXEC文件描述符標誌的值。

F_GETFD       : 對應於fd的文件描述符標誌做爲函數值做爲返回。當前只定義了一個文件描述符標誌FD_CLOEXEC

F_SETFD       : 對於fd設置文件描述符標誌。新標誌值按第三個參數設置。

F_GETFL        : 對應fd的文件狀態標誌做爲函數值返回,其返回值和open的標誌位一致。

F_SETFL                 : 將文件狀態標誌設置爲第三個參數的值:能夠更改的幾個標誌是:O_APPEND、O_NONBLOCK、O_SYNC、O_DSYNC、O_RSYNC、O_FSYNC和O_ASYNC

F_FETOWN          : 獲取當前接受SIGIO和SIGURG信號的進程或進程組ID

F_SETOWN             :設置SIGIO和SIGURG信號的進程ID或進程組ID。正的arg指定一個進程ID,負的arg指定一個進程組ID。

#include "apue.h"
#include <fcntl.h>

int main(int argc, char *argv[])
{
    int val;
    if(argc != 2)
    {
        err_quit("usage : a.out <descripor#>");
    }
    
    if((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
    {
        err_sys("fcntl error for fd %d\n", atoi(argv[1]));
    }
    
    switch(val & O_ACCMODE)
    {
    case O_RDONLY:
    printf("read only");
    break;
    case O_WRONLY:
    printf("write only");
    break;
    case O_RDWR:
    printf("read write");
    break;
    default:
    err_dump("unknow access mode");     
    }
    
    if(val & O_APPEND)
    {
        printf(", append");
    }
    
    if(val & O_NONBLOCK)
    {
        printf(", nonblocking");
    }
    
    if(val & O_SYNC)
    {
        printf(", synchronous writes");
    }
    
// #if !defined_ ( _POSIX_C_SOURCE) && defined_(O_FSYNC) && (O_FSYNC != O_SYNC)
    if(val & O_FSYNC)
    {
        printf(", synchronous writes");
    }
// #endif

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

3-5:對於指定的描述符打印文件標誌

  在修改文件描述符標誌或文件狀態標誌時必須謹慎,先要得到如今的標誌值,而後定期望值修改他,而後設置新標誌值。不能只是執行F_SETFD或F_SETFL命令,這樣會關閉之前設置的標誌位:

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");
    }
}

3-6:對一個文件描述符開啓一個或多個文件狀態標誌

  在Unix系統中,一般write只是將數據排入隊列,而實際的寫磁盤操做則可能在之後的某個時刻進行。而數據庫系統則須要使用O_SYNC,這樣一來,他從write返回時就知道數據已確實寫到了磁盤上,以避免在系統異常時產生數據丟失。數據的安全性獲得了保證,其代價是設置O_SYNC會顯著增長系統時間和時鐘時間。

十4、函數ioctl和/def/fd

  iotl函數一直是I/O操做的雜物箱。不能用本章其餘函數表示的I/O操做一般都能用ioctl標識。終端I/O是使用ioctl最多的地方。

  較新的系統都提供名爲/dev/fd的目錄,其目錄項是名爲0、一、2等的文件。打開文件/dev/fd/n等效於複製描述符n。

相關文章
相關標籤/搜索