本文幫你在 Unix 下玩轉 C 語言

  • shell是一種特殊的應用程序(命令行解釋器),他爲運行其他應用程序提供了一個接口。
  • posix規範了操作系統是什麼樣
  • 每個進程都有一個工作目錄(又叫當前目錄),相對路徑都是從工作目錄開始解釋。
  • Ctrl+D是文件結束字符
  • read讀指定字節數;fgets是讀取一行
  • 三個進程控制函數:fork exec waitpid。 waitpid【此函數獲取信息,釋放資源】父進程等待子進程終止,可以得到子進程何時終止。system函數是在exec外包了一層。
  • execlp要求參數以null結束,換行符不可以
  • 線程id只在它所屬進程內起作用,在另一個進程中無意義,可以使用線程id引用相應的線程。
  • 一個用戶可以屬於多至16個組
  • ctrl+c中斷鍵,ctrl+\退出鍵,等價於kill函數。kill(pid, SIGTERM)向另一進程發信號,發起信號的必須是該進程的所有者。
  • (gdb)set follow-fork-mode child使gdb進入子進程,事實證明不設置(默認調試父進程)這句無法進入pid==0的語句塊。子進程exit後無法再設置斷點gdb信息丟失,此時run可能啓動的不是父進程而是孫進程。
  • fork會複製fork開始直到函數結束的代碼【共享代碼正文,但複製全部變量】
  • 日曆時間:1970至今秒數,time_t類型用於保存這種時間。
  • 進程時間:cpu時間,clock_t類型用於保存這種時間。
  • 系統cpu時間是進程執行內核程序的時間。執行用戶指令的時間是用戶cpu時間。兩者之和是cpu時間。時鐘時間【牆上鍾時間】,是進程運行的時間總量,和進程數有關。time ls【ls可換成任意程序名】 查看時間。
  • clock_t times(struct tms* buf)成功返回牆上鍾時間【必須使用相對值,做差】
  • 庫函數不一定調用系統調用。應用程序可以直接調用系統調用,也可以通過C庫函數調用系統調用。
  • ISO C標準有24個頭文件(包括stdlib.h,stdio.h)。
  • 接口即協議。
  • 很多程序需要爲路徑分配存儲區
  • 守護進程:後臺運行且不與終端相連接的一種進程。
  • 與文件或目錄無關的選項用sysconf確定,與文件或目錄有關的選項用pathconf,fpathconf確定。
  • unix系統的大多數文件I/O只需要用到5個函數:open close read write lseek,都是不帶緩衝的I/O。不帶緩衝指的是read write都調用內核的一個系統調用。不帶緩衝的io不是iso c的組成部分,是posix的組成部分。
  • 對內核而言,所有的打開的文件都通過文件描述符(非負整數)引用。0 1 2 分別是輸入 輸出 錯誤 的描述符。文件描述符變化範圍0-OPEN_MAX(表示每個進程可以打開OPEN_MAX個文件)。
  • open函數:int fileId【返回最小的未用文件描述符數值】 = open(tmpPtr->_fileName【文件名】,O_RDWR【讀、寫打開】|O_CREAT【如果不存在則創建】, 0666【配合O_CREATE指定新文件訪問權限】);
  • close(fileId);關閉文件同時釋放進程加在該文件上的所有記錄鎖。進程終止時內核自動關閉它打開的文件。
  • 返回文件偏移量【偏移量始終存在,讀、寫操作從它指向的位置開始】=lseek(fileId,offset【每一個打開的文件都有一個當前文件偏移量,默認0,除非指定O_APPEND】,SEEK_SET【將偏移量設爲文件開始處offset字節】)
  • lseek返回-1說明文件描述符對應的文件是管道、fifo或網絡套接字。某些設備允許負的偏移量。
  • od -c 文件名 【-c表示以字符方式打印文件內容】 ls -ls 查看文件佔用多少個磁盤塊
  • nRead【返回讀到字節數】 = read(flag_fd【文件描述符】, buffer【讀取數據到buffer中】, length【一次讀取字節數】) 【成功返回前,偏移量增加讀到的字節數】
  • int bytes_write【返回寫入字節數】 = write(fileHandle,ptr,writeSize【寫入字節數】) 【寫操作從當前偏移量開始,成功後偏移量自動增加寫入字節數】
  • 測量文件讀寫由於緩存機制,在第一次之後可能不準確。
  • 每個進程都有一張打開文件描述符表->文件表(當前文件偏移量)->v節點信息
  • 可能有多個文件描述符指向同一文件表項,多個文件表項指向一個v節點表。多進程讀同一個文件沒有問題,但是寫同一個文件會有問題->原子操作。
  • open中用O_CREAT和O_EXCL可以將測試和創建合併爲一個原子操作。原子操作指多步組成的操作要麼執行完所有步驟,要麼一步也不執行。
  • 先lseek再write不可能是原子操作。兩個函數間內核可以掛起進程。
  • pread(..., off_t offset) pwrite(..., off_t offset) 相當於順序調用lseek和read,與順序調用的區別:無法中斷、不更新文件指針
  • O_APPEND方式打開文件,每次write,文件偏移量自動定位到文件尾。
  • 新的文件描述符 = dup(int filedes) dup2(int filedes【被複制】,int filedes2【指定數值】) 複製現存的文件描述符,與參數filedes共享同一個文件表項。fcntl(..)也可以複製文件描述符。
  • sync將塊緩衝區排入寫隊列,不等實際寫磁盤。fsync對單一文件起作用,等寫磁盤結束返回,更新屬性。fdatasync隻影響文件的數據部分。
  • fcntl(..)返回值和命令有關,可以返回文件狀態,文件描述符。可以修改文件狀態。
  • 5<>temp表示在文件描述符5上打開文件供讀寫。
  • 終端I/O是 ioctl的最大使用方面。
  • digit1 > &digit2表示要將digit1重定向至描述符2的同一個文件。
  • shell從左到右處理命令
  • struct stat sA【stat結構體包含磁盤號,所有者,訪問修改時間等屬性】; int retA【返回小於0表示文件不存在】 = stat(fileNameA.c_str(),&sA【stat函數將填寫sA】); ls -l就是使用的stat(...)函數
  • lstat(...)的增強功能是檢測符號鏈接
  • 文件類型信息包含在stat結構的st_mode成員中,有下面幾種類型。
    普通文件【包含某種數據的文件,數據是文本還是二進制對內核而言無區別,對文件內容的解釋由處理該文件的應用程序進行。例外:二進制可執行文件遵守內核理解的統一格式】
    目錄文件【包含其他文件的名字以及指向與這些文件有關信息的指針】
    塊設備文件【磁盤,提供對設備帶緩衝的訪問】
    字符設備文件【鍵盤,提供對設備不帶緩衝的訪問】
    FIFO 又名管道文件,shell裏的豎線 | 【用於進程間通信】
    套接字【這種文件用於進程間的網絡通信,也可用於一臺機上進程間的非網絡通信】
    符號鏈接【這種文件類型指向另一個文件】






  • 進程間通信(IPC)對象也表示爲文件:消息隊列、信號量、共享存儲對象。
  • 執行一個程序時exec(...)會保存有效用戶ID和有效組ID。通常有效ID==實際ID。
  • 當文件的有效用戶ID設置爲文件所有者ID時,如果所有者爲root,即使被一個普通用戶執行,該進程也具有超級權限。
  • 文件訪問權限:第一個規則是我們用名字打開一個文件時,對該名字包含的每一個目錄,包括她可能隱含的當前工作目錄(./)都應具有執行權限。對文件有適當的權限,取決於以何種方式打開。
  • 對目錄的讀權限使我們可以獲得該目錄所有文件名列表。對目錄的執行權限使我們可以通過該目錄,也就是【搜索】該目錄,尋找一個特定的文件名。
  • 創建文件需要對目錄有寫權限和可執行權限。刪除文件需要對目錄有寫和可執行權限【實際是減少文件i節點的一個連接數而已,文件本身還存在】,對文件本身不需要有讀、寫權限【刪除對文件本身沒讀沒寫】。
  • 新文件的用戶ID設置爲進程的有效用戶ID。新文件的組ID可以是:1.進程的有效組ID。2.它所在目錄的組ID。
  • access(pathname, mode)按實際用戶ID,和實際組ID進行訪問權限測試。只有root能chown.
  • umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);設置進程的文件模式創建屏蔽字
    creat("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |S_IROTH | S_IWOTH)
    先後運行上面兩行的運行結果-rw------- bar
    chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) fchmod(fildes, mod)
    運行結果-rw-r--r-- bar



  • -rw-rwSrw- S表示設置組ID【有效用戶ID和組ID】位已設置【有效用戶ID變成文件所有者的ID】,同時,組執行位則未設置。
  • linux交換區==windows下虛擬內存
  • chmod a+t 目錄 設置粘住位
  • 粘住位:可執行程序正文副本保存在交換區。目錄設置了粘住位,只有對目錄有寫權限加上1.擁有文件;2.擁有目錄;3.root三種之一 纔可以刪除或更名目錄下的文件。
  • chown fchown lchown更改文件用戶ID
  • truncate(pathnane, length) ftruncate(filedes, length) 截斷文件或創建空洞
  • 磁盤可分爲多個區,不同的區有不同的文件系統。
  • 目錄項【目錄/文件名】->i節點->實際數據塊。多個目錄項可以指向同一個i節點,例如軟連接和目錄本身指向的是同一塊數據,就應該指向的是同一個i節點。mv只更改目錄名,不移動實際數據。
  • link(existpath, newpath)創建一個新的目錄項,增加鏈接數;unlink(pathname)刪除目錄項,將pathname所引用的文件鏈接數減1. 目錄項刪除後看不見文件,但文件仍有可能佔據磁盤空間直至被內核刪除。
  • ./a.out & 表示後臺運行
  • 如果打開文件的進程數和鏈接數同時爲0,內核會刪除該文件。
  • remove(pathname)解除對一個目錄或文件的鏈接。rename(oldname, newname)
  • 普通目錄項和文件本身的關係是硬鏈接,她直接指向文件的i節點。符號鏈接是指向一個文件的間接指針,可以跨不同的文件系統。要注意函數是否跟隨符號鏈接。
  • symlink(actualpath, sympath)創建符號鏈接。readlink(pathname, buf, bufsize)打開鏈接本身,並讀鏈接中的名字。
  • ls -lt默認按文件修改時間排序,-u按訪問時間,-c按更改狀態時間。utime(pathname, times)更改文件的訪問和更改時間。
  • mkdir(pathname, mode)創建一個新的空目錄。rmdir(pathname)刪除一個空目錄。
  • DIR opendir(pathname) struct dirent readdir(DIR *dp) chdir(...)【當前工作目錄是進程的一個屬性,chdir隻影響進程本身】 fchdir(...) getcwd(...)獲得完整絕對路徑
  • 標準I/O庫【ISO C標準】文件操作圍繞文件描述符,也可以理解成圍繞流(stream)。當用標準io打開或創建一個文件時,我們已使一個流與文件關聯。標準IO最終都要調用read,write。
  • FILE結構包含:文件描述符、緩衝區指針、緩衝區長度、當前緩衝區字節數以及出錯標誌。文件指針是FILE*
  • 標準輸入輸出的文件指針是stdin,stdout,stderr。io庫提供緩衝的目的是減少使用read和write的調用次數。標準io函數通常調用malloc獲得緩衝區。
  • setbuf(FILE , buf, mode ,size)更改緩衝類型。 fflus(FILE fp)此函數使該流所有未寫的數據都被傳送至內核。
  • FILE *fdopen(filedes, type)使已有的文件描述符和流關聯。
  • FILE freopen(pathname, type, FILE restrict fp)在一個指定的流上打開文件,若流已打開,先關閉流。一般用於將指定文件打開爲一個預定義的流:輸入,輸出,錯誤。
  • FILE *fopen(pathname, type【r+b,加號表示讀和寫】)打開一個指定的文件,b區分文本和二進制,對unix無用。 cache中用的都是open
  • int fclose(FILE *fp)關閉一個打開的流。
  • 讀寫結構fread fwrite
  • 一次一行fgets fputs
  • 一次一個字符getc(FILE fp) fgetc(FILE fp) getchar(void) getchar等價於getc(stdin)。 出錯或到達文件尾,三個函數返回同樣的值,爲了區分需要ferror(FILE fp) feof(FILE fp) void clearerr(FILE *fp)
  • int ungetc(int c, FILE *fp)將字符再壓送回流中。
  • 一次一個字符輸出函數putc(int c, FILE) fputc(int c, FILE) putchar(int c)
  • 調用函數時間長於調用宏;一次系統調用比普通函數調用更費時間。
  • 每次一行io的函數:char fgets(buf,n,FILE)從指定流讀。 char gets(buf)從標準輸入讀。 輸出:fputs(str, FILE) puts(str)
  • 二進制IO:size_t fwrite(&struct[2], sizeof(struct), 4, FILE* fp) 將一個數組的第2-5號元素寫在一個文件上
  • fread(..) 只能處理統一系統上的數據,異構系統通過網絡互連時不行,不同系統間交換二進制數據需要使用較高級的協議。
  • 定位流:ftell(FILE) fseek(FILE, offset, whence【SEEK_SET】) rewind(FILE*) fgetpos(..) fsetpos(...) 文件描述符是用lseek
  • int fileno(FILE fp)獲得文件描述符 , FILE tmpfile(void)創建臨時文件
  • $TMPDIR=.. ./a.out 在程序名前指定環境變量
  • int printf(format,...)將格式化數據寫到標準輸出。 vprintf(format, va_list arg) vfprintf(...,va_list arg) vsprintf vsnprintf 可變參數表(...) 變成了arg
  • int fprintf(FILE* fp, format, ...)寫至指定的流
  • int sprintf(buf, format)將格式化的字符串寫入數組buf中,在數組尾端自動加null字節
  • int snprintf(buf, size_t n,format, ...) 與sprintf基本一樣,n指定了緩衝區長度,超過就丟棄避免溢出
  • int scanf(format, ...) sscanf(cmdline【源】, "%s %s", opt[0], opt[1]【目的】)
  • int fscanf(FILE *fp, format, ...)
  • int sscanf(buf, format, ...) vscanf(format, va_list arg)等等
  • struct passwd getpwnam(const char name)獲取口令文件項
  • struct tm結構用於保存時間的年月日的形式。
  • gettimeofday(struct timeval *res, NULL)微秒級
  • time_t time(time_t* calptr)返回當前時間,calptr不空,時間值放其中。
  • struct tm localtime(const time_t ptr)他和gmtime(..)的區別是他把日曆時間轉換爲本地時區時間,gmtime轉換成國際標準時間。
  • time_t mktime(struct tm* ptr)以本地時間作爲參數,將其轉換爲time_t值【日曆時間:1970至今】。
  • char asctime(struct tm)返回指向年月日字符串的指針。char ctime(time_t * prt)返回指向日曆時間的指針。
  • size_t strftime(...)按格式控制時間字符串
  • timeval指定秒和微秒、timespec指定秒和納秒
  • 正常終止一個程序:exit()默認包含關閉流操作【FILE存儲區清0】 在main中exit(0)等價於return(0)
  • int atexit(void (*func)(void))登記的函數會被exit函數以相反的順序調用。
  • 內核執行程序的唯一方法是exec。進程自願終止的唯一方法exit【顯式或隱式】。非自願的需要給一個信號終止。
  • extern char **environ環境指針 getenv putenv 訪問特定環境變量
  • a.out的符號表段、調試信息段、動態共享庫鏈接表段不裝載到進程執行的程序映像中。 size a.out 報告正文段、數據段、bss段的長度
  • cc -static hello1.c 阻止使用共享庫。 cc默認使用共享庫
  • void* malloc(size_t size)存儲區初始值不確定
  • void* calloc(size_t nobj, size_t size)爲指定數量指定長度的對象分配存儲區,初始化爲0
  • void realloc(void ptr, size_t newsize)更改以前的長度,新增部分初始值不確定,老部分保留內容。
  • void free(void* ptr)
  • goto語句不能跨越函數,setjump longjmp可以處理嵌套調用中出錯情況【否則只能檢查返回值逐層返回麻煩】。在希望返回的位置int setjmp(jmp_buf env【env爲全局纔多個函數可見】),出錯位置int longjmp(env,8)。
  • "str1" "str2"等價於"str1str2"。爲IO庫分配緩衝區應全局靜態或動態alloc分配。
  • 編譯器進行優化時,它有時會取一些值的時候,直接從寄存器裏進行存取,而不是從內存中獲取,這種優化在單線程的程序中沒有問題,但到了多線程程序中,由於多個線程是併發運行的,就有可能一個線程把某個公共的變量已經改變了,這時其餘線程中寄存器【線程各自有寄存器】的值已經過時,但這個線程本身還不知道,以爲沒有改變,仍從寄存器裏獲取,就導致程序運行會出現未定義的行爲。
  • 自動變量不想回滾,可以定義爲volatite【易失】屬性。易失屬性告訴編譯器不要優化,在其他地方會改變值,優化可能將這個變量一直放到寄存器中。
  • int getrlimit(int resource, struct rlimit *rlptr) setrlimit可以查詢和更改資源限制。shell中的ulimit。
  • getpid getppid【獲得父進程id】 getuid geteuid getgid getegid【有效組id】
  • pid_t fork(void) fork返回兩次 clone,父返子,子返0.父子進程執行fork之後的代碼,父子共享正文不共享數據,共享文件表和i節點。寫時複製(copy-on-write)寫時複製,只讀時共用。
  • vfork在子進程調用exec或exit之前,他在父進程的空間中運行,調用exec或exit之後父進程才繼續運行。
  • 標準IO庫printf是帶緩衝的。標準輸出連到終端是行緩衝【打印】,否則是全緩衝。定向到文件是全緩衝
  • 信號可由進程自身產生【abort】、其他進程【kill(pidid,sig)】或內核產生。
  • 父進程提前終止的的子進程由init【init中默認有wait】進程領養。內核爲每個終止的子進程保存了一定量的信息,父進程用wait或waitpid得到這些信息。
  • 一個長期運行的進程fork很多子進程,除非手動wait,否則會出現很多僵死進程。
  • pid_t wait(int statloc) pid_t waitpid(pid_t pid【等待pid號進程】, int statloc【指向終止狀態】, int options)【成功返回進程id、0、失敗返回-1】。 如果收到SIGCHLD信號調用wait,可以立刻返回,如果任意時刻調wait,可能會阻塞直到有一個子進程終止。
  • wait3 wait4比waitpid多了一個功能是最後一個參數會返回所有子進程使用資源情況的彙總。
  • 競爭條件:多進程處理共享數據,數據的結果和處理順序有關。父等子死用wait,子等父死 【輪詢】while(getppid() != 1) sleep(1);等於1是init進程id。爲1說明父進程死了,被init接管了。
  • exec不創建新進程,進程ID不變。exec只是用一個全新的程序替換當前進程的正文、數據、隊、棧。execl execv execle execve execlp execvp
  • 所有.c文件查找字符串abort的指令$ grep abort .//.c
  • 任何時候都可以調用int setuid(uid_t uid)做下兩種操作:有效用戶ID=實際用戶ID;有效用戶ID=保存的設置用戶ID【exec複製有效用戶ID得來的(一般是文件所有者?)】。設置用戶ID的程序,fork後,exec之前要改回普通權限,不應使用system函數。
  • #suspend $fg 作業控制
  • shell中awk實際是shell先fork->exec(awk)->wait來運行的。
  • char* getlogin(void)獲取登錄名。找到運行該程序的用戶登錄名getpwuid(getuid())
  • 網絡登錄telnetd進程fork,父負責網絡連接的通信,子執行login,父子間通過僞終端相連接。
  • 進程組是一個或多個進程的集合。getpgid setpgid設置指定進程或調用進程的組ID。
  • 會話是一個或多個進程組的集合。進程調用pid_t setsid(void)建立一個新會話。進程是首進程、組長、斷開所有控制終端。pid_t getsid(pid_t pid)返回會話首進程的進程組ID。
  • secureCRT是終端,對應前臺進程組【終端(終端也是文件描述符)關聯的進程】,控制進程組【shell】,後臺進程組【&讓其後臺運行】,加在一起是會話。
  • 一個作業是幾個進程的集合,通常是一個進程的管道線。vi main.c【前臺啓動了一個作業】 pr *.c | lpr & | make all & 【後臺啓動了兩個作業,兩個作業調用的所有進程都後臺運行】
  • 終端驅動程序產生信號進而影響前臺進程組的方法:中斷字符ctrl+C 退出字符ctrl+\ 掛起字符 ctrl+Z。 可以用信號使後臺作業暫停,fg %1 使1號作業轉爲前臺作業
  • 進程屬於進程組,進程組屬於一個會話,會話可能有也可能沒有控制終端。前臺進程組ID是終端的屬性,不是進程的屬性。
  • 管道線的最後一個進程是shell的子進程,執行管道的其他命令都是最後一個進程的子進程。前端進程組ID==sessionID時說明他是後臺進程。
  • 不是孤兒進程組的條件:該進程組中有一個進程,其父進程屬於同一個會話的另一個組。
  • 信號SIGKILL SIGSTOP不能忽略,不能捕捉。
  • core文件複製進程終止時的存儲映像。
  • kill命令和kill函數只是將一個信號送給一個進程或組,進程是否終止取決於信號的類型,以及進程是否安排了捕捉該信號。$kill -USR1 7216
  • void (signal(int signo, void (func)(int)))(int)成功返回信號以前的處理配置,失敗返回SIG_ERR。不改變信號的處理方式,就不能確定信號當前的處理方式。func指定SIG_IGN或SIG_DEL表示忽略或默認處理。
  • exec使捕捉失效,捕捉函數的地址可能無意義。
  • 進程捕捉到信號執行信號處理函數func,執行完後執行發生信號時正在執行的代碼【pause函數能使進程掛起直到捕捉到一個信號】。處理第一次信號後是否將信號動作復位爲默認值?
  • read write部分數據時被中斷算成功還是失敗可以選擇。
  • 在信號處理程序中調用一個不可重入函數,結果是不可預見的。
  • raise(int signo) == kill(getpid(), int signo) 進程將信號發送給其他進程需要權限。向一個不存在的進程發空信號,kill返回-1.
  • 進程ID會重新使用。
  • signal函數的語義與實現有關,最好使用sigaction函數。sigaction(signo【要檢測或修改的具體動作的信號編號】, &act【非空則修改其動作】, &oact【非空則返回信號的上一個動作】)
  • sigemptyset(&act.sa_mask)【初始化由set指向的信號集清除其中所有信號】
  • 在處理一個給定的信號時,如果這種信號再次發生,通常並不將他們排隊,會被阻塞到對前一個信號處理結束爲止。阻塞結束後內核只傳遞這種信號一次。【屏蔽字爲0代表沒有信號阻塞,執行哪個信號的處理函數屏蔽哪個信號】
  • unix低速系統調用阻塞期間【磁盤IO一般不阻塞】如果接受到一個信號,則該低速系統調用被中斷。
  • void abort(void)使異常程序終止。子進程終止會向父進程發送SIGCHLD信號。sig2str str2sig是信號編號和信號名相互轉換函數。
  • 多線程程序在單處理器運行仍然能改善響應時間和吞吐量。
  • 線程ID只在它所屬的進程環境中有效,因此可以不唯一。
  • pthread_t pthread_self(void)獲得自身線程的ID。主線程可以用線程ID控制哪個線程處理哪些作業。新線程和主線程之間有競爭,使用主線程返回的線程id並不安全。線程ID如果很長那估計是地址。
  • 如果任一線程調用exit,_Exit,_exit整個進程就會終止。線程終止方式:1.啓動函數返回。2被同進程其他線程取消【線程可以忽略取消】。3 pthread_exit
  • void pthread_exit(void* rval_ptr) int pthread_join(pthread_t thread, void** rval_ptr【保存線程的終止狀態】)【阻塞直到線程返回】
  • 線程裏面聲明的東西別往出帶。線程從線程函數返回終止,清理程序就不被調用。waitpid==pthread_join。pthread_detach使線程分離【對線程終止狀態不感興趣】,分離線程終止時資源被回收,分離的線程無法pthread_join。
  • 加鎖的一種場景:對引用計數加1、減1以及檢查是否爲0之前都要鎖住互斥量。【引用數類似文件的link】
  • 讀寫鎖以讀模式鎖住是共享模式【併發讀】,以寫模式鎖住是獨佔模式【獨自寫】。
  • 線程的虛擬地址空間是多個線程共用,如果線程多,會不夠用。遞歸類型互斥量可以遞歸加鎖。
  • 線程和信號都涉及函數可重入的問題。信號:捕捉函數如果向全局數據寫會錯。線程:多個線程同時調用同一函數。每個線程有各自的信號屏蔽字。信號處理函數進程內共享。
  • errno被重新定義爲線程私有數據。鍵用來保護線程私有數據。
  • 包含多線程的進程fork時只有fork的線程被複制進子進程,鎖的情況無法控制,如果馬上exec就可以避免。
  • pread(...)使偏移量的設置和數據讀取成爲一個原子操作。
  • ps -a【顯示其他用戶所擁有的進程狀態】x【沒有控制終端的進程狀態】j【會話ID、進程組ID。。】
  • 創建守護進程兩次fork,就不是會話首進程,不會取得控制終端。fork保證子進程不是進程組組長,可以setsid。
  • lockfile(fd)對文件加鎖 lockf(lockfd, F_TLOCK, 0L)可以確保只有一個守護進程運行。
  • 低速系統調用是可能會使進程永遠阻塞的一類系統調用。
  • 非阻塞IO:操作無法完成,立即出錯返回【不停在那,以便進行下一步處理,類似trylock試加鎖】。兩種方法指定描述符爲非阻塞IO:open時O_NONBLOCK;fcntl(fd, cmd, &lock)打開 O_NONBLOCK標誌。
  • 記錄鎖==字節範圍鎖:當一個進程讀或修改文件某部分時,可以阻止其他進程修改同一文件區。有些系統中文件的最後狀態取決於寫該文件的最後一個進程。
  • 同一進程可對同一字節範圍重複加鎖,新鎖換老鎖。可以測試另一個進程是否對某記錄加鎖。
  • 鎖是與進程、文件兩者相關聯的。fork出的子進程不繼承父進程對文件的鎖【避免父子同時寫一個文件】。exec新程序繼承原程序的鎖。
  • 某些unix提供系統調用跟蹤特性。
  • STREAM:構造內核設備驅動程序和網絡協議包的一種通用方法。
  • IO多路轉接【兩個描述符】:執行阻塞read,阻塞是對整個進程阻塞,如果多個通路【一般是無限循環讀、寫】想要相互不影響,就得fork多個進程,每個進程處理各自的文件描述符。用非阻塞read輪詢描述符消耗cpu。
  • IO多路轉接思想:構造一張描述符表,調用一個函數,直到表中描述符中的一個已經準備好IO時,該函數返回,告訴進程哪些描述符可以IO。主要用於終端IO和網絡IO。select(0, NULL, NULL, NULL, &tv)相當於sleep了,精確到微秒。
  • 異步IO:基本思想,告訴內核,當一個描述符已準備好可以進行IO時,用一個信號通知它【它指應用程序】。系統V異步IO調ioctl設置信號處理,只對STREAMS設備和STREAMS管道起作用。 BSD異步IO設置信號SIGIO處理程序,調fcntl設置O_ASYNC文件爲異步IO。只對終端和網絡描述符有效。
  • 存儲映射IO:【將一個給定文件映射到一個存儲區域】unsigned char mmapBuf = (unsigned char)mmap(NULL【區域起始地址】, fileSize, PROT_READ【映射區可讀】, MAP_SHARED ,fd【被映射文件】, 0【映射字節在文件中起始偏移量】) munmap((char*)mmapBuf, fileSize)【解除映射】 msync沖洗到磁盤
  • IPC【InterProcess Communication】:各種管道、消息隊列、信號量、共享存儲、套接字、STREAMS【僅後兩種支持不同主機進程間通信】
  • 管道:半雙工【數據只能在一個方向上流動】;只能在公共祖先的進程間使用,通常fork後父子間使用。int pipe(int filedes[2]) fork後f[0]<-【內核自動?】-f[1] 有兩份,各關閉一個
  • sh -c cmdstring表示shell將擴展字符串中的特殊字符【*.c】。
  • ${PAGE:-more}如果PAGE已定義,使用,否則用more。
  • 對管道標準IO默認全緩衝。
  • 通過FIFO【命名管道】不相關的進程也能交換數據。int mkfifo(pathname, mode_t mode)類似於創建普通文件。
  • 創建IPC結構:msgget semget shmget 要指定一個鍵key_t。 ftok可由一個路徑名和項目ID產生一個鍵key_t ftok(path, id)
  • msgctl semctl shmctl修改uid、gid、mode 三種IPC都有內置限制,可通過配置內核修改。 ipcs查看 ipcrm刪除
  • msgrcv可以是非先進先出
  • 信號量的值代表對應資源是否可以使用。semop(_ID, buf[]【數組中操作要麼都執行,要麼都不執行】, 1)表示等待信號量、釋放資源、獲取資源。semctl取信號量信息、設置信號量信息。
  • 使用信號量【實際上是同步原語而不是IPC】,先創建一個包含一個成員的信號量集合,信號量值賦初值1.分配資源時sem_op爲-1調用semop,釋放資源sem_op爲1調用semop。每次設置SEM_UNDO,以處理進程終止還有未釋放資源的情況。
  • shmget既可以創建,也可以引用已有的【msgget一樣】。 shmctl IPC_RMID減少引用數,不真正刪除。shmid和pickey不一樣,shmget返回值是shmid 。shmdt脫接不刪除,引用數減一。
  • 套接字用於不同計算機上的進程相互通信,其它進程運行位置透明。可以採用許多網絡協議,TCP/IP常見。
  • 創建一個套接字int socket(int domain【例如ipv4internet網域】, int type, int protocol)返回套接字文件描述符。
  • int shutdown(int sockfd, int how)禁止套接字上的輸入輸出。uint32_t htonl(uint32_t hostint32)等進行處理器字節序和網絡字節序的轉換。
  • inet_pton( AF_INET, host.c_str(), &m_addr.sin_addr)將文本字符串轉換成網絡字節序的二進制地址
  • poll select函數能檢查文件描述符的狀態,用來決定是否對文件描述符執行某種操作。
  • setsockopt(_sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeo, len)
  • int fattach(int fileds, const char* path)使STREAMS管道和文件系統中的一個名字關聯。
  • unix域套接字用於同一機器上進程間通信。int ssocketpair(int domain, int type, int protocol, int sockfd[2])
  • 終端IO:函數tcgetattr tcsetattr 終端IO控制函數大多tc開頭
  • 很多數據庫實現都採用兩個文件:索引文件和數據文件。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章