1.1引言
1.2unix體系結構
The interface to the kernel is a layer of software called thesystemcalls(the shaded
portion in Figure 1.1).
1.3登入
1.登入名
sar:x:205:105:Stephen Rago:/home/sar:/bin/ksh
登入名、加密密碼、數字使用者ID(205)、數字組ID(105)、注釋字段、起始目錄(/home/sar)、shell程式(/bin/ksh)
2.shell
1.4檔案和目錄files and directories
1.檔案系統
根的目錄,“/”
目錄是一個包含目錄項的檔案。
The statandfstatfunctions(stat和fstat函數) return a structure of information containing all the attributes of a file.
2.檔案名
3.路徑名
相對/絕對路徑名
相對路徑名指向相對于目前目錄的檔案
opendir函數傳回指向DIR結構的指針,并将該指針傳向 readdir函數。我們并不關心 D I R結構中包含了什麼。
然後,在循環中調用readdir來讀每個目錄項。它傳回一個指向 d i r e n t結構的指針,而當目錄中已無目錄項可讀時則傳回 n u l l指針。
在d i r e n t結構中取出的隻是每個目錄項的名字 ( d _ n a m e )。使用該名字,此後就可調用 s t a t函數(見4 . 2節)以決定該檔案的所有屬性。
#include "apue.h"
//它包含了某些标準系統頭檔案,定義了許多常數及函數原型
#include <dirent.h>
int
main(int argc, char *argv[])
//取指令行的第1個參數a rg v〔1〕作為列出的目錄名
{
DIR *dp;
struct dirent *dirp;
if (argc != 2)
err_quit("usage: ls directory_name");
/*各種不同U N I X系統的目錄項的實際格式是不一樣的,是以使用函數opendir, readdir和closedir處理目錄*/
if ((dp = opendir(argv[1])) == NULL)
err_sys("can’t open %s", argv[1]);
while ((dirp = readdir(dp)) != NULL)
printf("%s\n", dirp->d_name);
closedir(dp);
exit(0);
}
注意,列出的目錄項不是以字母順序排列的,l s指令則一般按字母順序列出目錄項。
4.工作目錄(working directory)
程序可以用c h d ir函數更改其工作目錄。
相對路徑名d o c /m e m o / j o e, d o c和m e m o都應當是目錄,但是卻不清楚j o e是檔案還是目錄。
路徑名 / u r s /l i b / l i n t是一個絕對路徑名,它指的是檔案 (或目錄) lint,而l i n t在目錄l i b中,l i b則在目錄u s r中,u s r則在根目錄中。
5.起始目錄
1.5 輸入和輸出
1.檔案描述符(file descriptor)
小的非負整數,核心用以辨別一個特定程序正在存訪的檔案
2.标準輸入、标準輸出和标準出錯(三個檔案描述符号)
ls > file.list //執行ls指令,其标準輸出重新定向到名為file. list的檔案上。
3.不用緩沖的i/o
函數o p e n、r e a d、w r i t e、l s e e k以及c l o s e提供了不用緩存的I / O。這些函數都用檔案描述符進行工作。
#include "apue.h"
#define BUFFSIZE 4096
int
main(void)
{
int n;
char buf[BUFFSIZE];
/*兩個常數STDIN_FILENO和STDOUT_FILENO定義在<unistd.h>頭檔案中,它們指定了标準輸入和标準輸出的檔案描述符。*/
/*它們的典型值是 0和1,但是為了可移植性,我們将使用這些新名字。*/
while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
if (n < 0)
err_sys("read error");
exit(0);
}
4.标準I/O
使用标準 I / O可無需擔心如何選取最佳的緩存長度,例如程式 1 - 2中的B U F F S I Z E常數。另一個使用标準 I / O函數的優點與處理輸入行有關 (常常發生在U N I X的應用中)。例如,f g e t s函數讀一完整的行,而另一方面, r e a d函數讀指定位元組數。
1-6 程式和程序
1.程式
程式(p r o g ra m)是存放在磁盤檔案中的可執行檔案。
2.程序和程序ID
程式的執行執行個體被稱為程序(p r o c e s s)。
每個U N I X程序都一定有一個唯一的數字辨別符,稱為程序 I D(process ID)。程序I D總是一非負整數。
函數getpid得到目前程序的ID。
3.程序控制
有三個用于程序控制的主要函數: f o r k、e x e c和w a i t p i d(e x e c函數有六種變體,但經常把它們統稱為e x e c函數)。
#include "apue.h"
#include <sys/wait.h>
int
main(void)
{
char buf[MAXLINE];
pid_t pid;
int status;
/* from apue.h */
printf("%% "); /* print prompt (printf requires %% to print %)*/
/*fgets傳回的每一行都以換行符終止,後随一個null位元組*/
while (fgets(buf, MAXLINE, stdin) != NULL)
{
/*strlen計算字元串長度,再用null(0)替換換行符*/
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = 0; /* replace newline with null */
/*fork建立一個新程序*/
if ((pid = fork()) < 0) {
err_sys("fork error");
}else if (pid == 0) {
/* child */
execlp(buf, buf, (char *)0);//fork配合execlp産生新程序
err_ret("couldn’t execute: %s", buf);
exit(127);
}
/* parent */
if ((pid = waitpid(pid, &status, 0)) < 0)//父親等兒子結束
err_sys("waitpid error");
printf("%% ");
}
exit(0);
}
•調用f o r k建立一個新程序。新程序是調用程序的複制品,故稱調用程序為父程序,新建立的程序為子程序。 f o r k對父程序傳回新子程序的非負程序 I D,對子程序則傳回0。因為f o r k建立一新程序,是以說它被調用一次 (由父程序),但傳回兩次(在父程序中和在子程序中 )。
•在子程序中,調用 e x e c l p以執行從标準輸入讀入的指令。這就用新的程式檔案替換了子程序。f o r k和跟随其後的e x e c的組合是某些作業系統所稱的産生一個新程序。在 U N I X中,這兩個部分分成兩個函數。
這裡有一點我的了解:execlp是exec一族中的一員,他的主要作用就是配合fork。産生新程序,那麼新的子程序執行啥代碼?
百度上看到的:如果函數調用成功,程序自己的執行代碼就會變成加載程式的代碼,execlp()後邊的代碼也就不會執行了.
也就是說,子程序從整個程式的頭開始執行,當子程序的fork和execlp又配合成功,就又有了孫子程序(自創的名字。。),這樣也就能夠解釋為啥一直有% 這個提示符産生了。
必須crtl+D結束。
•子程序調用 e x e c l p執行新程式檔案,而父程序希望等待子程序終止,這一要求由調用w a i t p i d實作,其參數指定要等待的程序 (在這裡, p i d參數是子程序 I D )。w a i t p i d函數也傳回子程序的終止狀态( s t a t u s變量)。在此簡單程式中,沒有使用該值。如果需要,可以用此值精确地确定子程序是如何終止的。
4.線程(thread)和線程id
Usually, a process has only one thread of control — one set of machineinstructions executing at a time.
All threads within a process share the same address space, filedescriptors, stacks,and process-related attributes. Each thread executes on itsown stack,although any thread can access the stacks of other threads in thesame process. Because they can access the same memory, the threads need tosynchronize access to shared data among themselves to avoid inconsistencies.