apue讀書筆記-第14章 高級IO


多路I/O轉接


與select函數不同,poll不是爲每個狀態(可讀性、可寫性和異常狀態)構造一個描述符集,而是構造一個pollfd結構數組,每個數組元素指定一個描述符編號以及其所關心的狀態


readv和writev函數


作用:在一次函數調用中讀、寫多個非連續緩存區


總結:應當用盡量少的系統調用次數來完成任務。如果只寫少量的數據,會發現自己複製數據然後使用一次write會比用writev更合算。但也可能發現,這樣獲得的性能提升並不值得,因爲管理中間緩衝區會增加程序複雜度。


readn和writen函數


針對管道、FIFO以及某些設備,特別是終端、網絡和STREAMS設備,一次讀、寫返回值可能小於要求值的情況,apue中定義了這兩個函數,用於處理這類情況。


用戶CPU時間、系統CPU時間、時鐘時間


在閱讀本章的過程,一直對三個概念比較模糊,即:用戶CPU時間、系統CPU時間、時鐘時間。參考了網上幾篇文章後,總結如下:

  • 時鐘時間:就是一個進程從開始運行到結束運行後,你的時鐘走過了多少時間,這其中包含了進程在阻塞和等待狀態的時間。

  • 用戶CPU時間:就是用戶的進程獲得了CPU資源以後,在用戶態執行的時間。

  • 系統CPU時間:用戶進程獲得了CPU資源以後,在內核態的執行時間。


習題


14.1

#include "apue.h"
#include <fcntl.h>
#include <errno.h>
void sigint(int signo)
{
}
int main(void)
{
    pid_t pid1, pid2, pid3;
    int fd;
    
    setbuf(stdout, NULL); // 將標準輸出設置爲無緩存
    signal_intr(SIGINT, sigint);
    if ((fd = open("lockfile", O_RDWR|O_CREAT, 0666) < 0))
    {
        err_sys("can't open/creat lockfile");
    }
    if ((pid1 = fork()) < 0)
    {
        err_sys("fork failed");
    }
    else if (0 == pid1)
    {
        if (lock_reg(fd, F_SETLK, F_RDLCK, 0, SEEK_SET, 0) < 0)
        {
            err_sys("child1: can't read-lock file");
        }
        printf("child1: obtained read-lock on file\n");
        pause(); // 使調用進程掛起直至捕獲一個信號 
        printf("child1: exit after pause\n");
        exit(0);
    }
    else
    {
        sleep(2);
    }
    if ((pid2 = fork()) < 0)
    {
        err_sys("fork failed");
    }
    else if (0 == pid2)
    {
        if (lock_reg(fd, F_SETLK, F_RDLCK, 0, SEEK_SET, 0) < 0)
        {
            err_sys("child2: can't read-lock file");
        }
        printf("child2: obtained read-lock on file\n");
        pause();
        printf("child2: exit after pause\n");
        exit(0);
    }
    else
    {
        sleep(2);
    }
    if ((pid3 = fork()) < 0)
    {
        err_sys("fork failed");
    }
    else if (0 == pid3)
    {
        // 0和SEEK_SET決定了加鎖區域的開始位置, 即從文件頭部開始偏移量爲0的地方開始加鎖
        // 加鎖失敗立刻返回
        if (lock_reg(fd, F_SETLK, F_WRLCK, 0, SEEK_SET, 0) < 0) // 長度爲0意味着到文件尾
        {
            printf("child3: can't set write-lock: %s\n", strerror(errno));
        }
        printf("child3 about to block in write-lock...\n");
        // F_SETLKW爲F_SETLK的阻塞版本, 若加鎖失敗則進程進入休眠, 直至可以加鎖或被信號中斷喚醒
        if (lock_reg(fd, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0) < 0)
        {
            err_sys("child3: can't write-lock file");
        }
        printf("child3 return and got write lock???\n");
        pause();
        printf("child3: exit after pause\n");
        exit(0);
    }
    else
    {
        sleep(2);
    }
    
    if (lock_reg(fd, F_SETLK, F_RDLCK, 0, SEEK_SET, 0) < 0)
    {
        printf("parent: can't set read-lock: %s\n", strerror(errno));
    }
    else
    {
        printf("parent: obtained additional read-lock while, write-lock is pending\n");
    }
    printf("killing child1...\n");
    kill(pid1, SIGINT);
    printf("killing child2...\n");
    kill(pid2, SIGINT);
    printf("killing child3...\n");
    kill(pid3, SIGINT);
    exit(0);
}


14.2

在Linux下fd_set的定義爲一個包含長整形數組的結構,爲什麼不直接定義成數組,原因是結構體之間可以通過C語言的賦值運算符直接賦值。

FD_* 都是通過內嵌彙編實現的位操作



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章