|
CSAPP上的例子,但是書中的源碼有問題,修改后的版本:
#include "csapp.h" #define MAXARGS 128
void eval(char *cmdline); int parseline(char *buf, char **argv); int buildin_command(char **argv);
int main() { char cmdline[MAXLINE];
while (1) { printf("> "); Fgets(cmdline, MAXLINE, stdin); if (feof(stdin)) exit(0);
eval(cmdline); } }
void eval(char *cmdline) { char *argv[MAXARGS]; char buf[MAXLINE]; int bg; pid_t pid;
strcpy(buf, cmdline); bg = parseline(buf, argv); if (argv[0] == NULL) return;
if (!builtin_command(argv)) { if ((pid = Fork()) == 0) { if (execve(argv[0], argv, environ) < 0) { printf("%s: Command not found.\n", argv[0]); exit(0); } } if (!bg) { int status; if (waitpid(pid, &status, 0) < 0) unix_error("waitfg: waitpid error"); } else printf("%d %s", pid, cmdline); } return; }
int builtin_command(char **argv) { if (!strcmp(argv[0], "quit")) exit(0); if (!strcmp(argv[0], "&")) return 1; return 0; }
int parseline(char *buf, char **argv) { char *delim; int argc; int bg;
buf[strlen(buf) - 1] = ' '; while (*buf && (*buf == ' ')) buf++;
argc = 0; while ((delim = strchr(buf, ' '))) { argv[argc++] = buf; *delim = '\0'; buf = delim + 1; while (*buf && (*buf == ' ')) buf++; } argv[argc] = NULL;
if (argc == 0) return 1;
if ((bg = (*argv[argc - 1] == '&')) != 0) argv[--argc] = NULL;
return bg; }
摘要: http://www.defmacro.org/ramblings/fp.html還是放在Mathematics類吧
Functional Programming For The Rest of Us
Monday, June 19, 2006
Introduction
Programmers are procrastinators. Get in, get some coffee, ... 閱讀全文
1. dup和dup2函數 #include <unistd.h> int dup(int filedes); int dup2(int filedes, int filedes2); // Both return: new file descriptor if OK, -1 on error
dup返回的file descriptor(以下簡稱fd)為當前可用的最低號碼,dup2則指定目的fd,如果該fd已被打開,則首先關閉這個fd。 dup后兩個fd指向相同的file table entry,這意味著它們共享同一個的file status flag, read, write, append, offset等。
事實上,dup等價于
fcntl(filedes, F_DUPFD, 0);
dup2和也類似于
close(filedes2);
fcntl(filedes, F_DUPFD, filedes2); 但這不是一個原子操作,而且errno也有一定的不同。
Appending to a File 考慮某個單一進程試圖在文件追加寫入的操作。由于早期的UNIX系統不支持O_APPEND選項,因此得先用lseek將offset置于文件尾部。 if (lseek(fd, 0L, 2) < 0) err_sys("lseek error"); if (write(fd, buf, 100) != 100) err_sys("write error"); 注意這里的lseek函數的第三個參數2等于SEEK_END常量,但是早期UNIX并沒有這個常量名(System V中才引進) 這樣的處理在多進程試圖在同一文件尾部追加寫入時就有可能出現問題。 假設兩個獨立線程A B要在某個文件尾部追加寫入,使用了上述方法,并沒有使用O_APPEND開關。 首
先A指向了該文件尾部(假設是offset=1500的地方),接著內核切換到B進程,B也指向了該尾部,然后寫入了100字節,此時內核把v-node
中當前文件的大小改為了1600。內核再次切換進程,A繼續運行,調用write方法,結果就在offset=1500的地方寫入了,覆蓋了B進程寫入的
內容。 這個問題其實和Java中的多線程差不多,指向文件尾部和寫入應該作為一個原子操作執行,就像Java中使用synchronized塊保護原子操作。使用O_APPEND選項就是一種解決方法。 另一種解決方法時使用XSI extension中的pread和pwrite函數。 #include <unistd.h> ssize_t pread(int filedes, void *buf, size_t nbytes, off_t offset); // Returns: number of bytes read, 0 if end of file, -1 on error ssize_t pwrite(int filedes, const void *buf, size_t nbytes, off_t offset); // Returns: number of bytes read, 0 if end of file, -1 on error 調用pread與調用lseek后再調用read等價,以下情況除外: 1. pread的兩個步驟無法被中斷。 2. 文件指針尚未被更新時。 pwrite與lseek+write的差別也相似。 Creating a File
當使用O_CREAT和O_EXCL開關調用open函數時,如果文件已經存在,則open函數返回失敗值。如果不使用這兩個開關,可以這樣寫:
if ((fd = open(pathname, O_WRONLY)) < 0) { if (errno == ENOENT) { if ((fd = creat(pathname, mode)) < 0) err_sys("creat error"); } else { err_sys("open error"); } }
當open函數執行后creat函數執行前另一個進程創建了同名文件的話,該數據就會被擦除。
內核使用三種數據結構表示一個打開的文件,他們之間的關系決定了進程間對于共享文件的作用。 Every process has an entry in the process table. Within each process table entry is a table of open file descriptors, which we can think of as a vector, with one entry per descriptor. Associated with each file descriptor are 1) The file descriptor flags (close-on-exec; refer to Figure 3.6 and Section 3.14) 2) A pointer to a file table entry The kernel maintains a file table for all open files. Each file table entry contains 1) The file status flags for the file, such as read, write, append, sync, and nonblocking 2) The current file offset 3) A pointer to the v-node table entry for the file Each open file (or device) has a v-node structure that contains information about the type of file and pointers to functions that operate on the file. For most files, the v-node also contains the i-node for the file. This information is read from disk when the file is opened, so that all the pertinent information about the file is readily available. For example, the i-node contains the owner of the file, the size of the file, pointers to where the actual data blocks for the file are located on disk, and so on.  上圖為這三種數據結構及其相互聯系 其中v-node主要用于提供單個操作系統上的多文件系統支持,Sun把它稱為Virtual File System linux中沒有v-node,使用了一個generic i-node代替,盡管使用了不同的實現方式,v-node在概念上與generic i-node相同。 下面來討論兩個獨立的進程打開同一文件的情況 這種情況下兩個進程擁有不同的file table,但其中的兩個指針指向了同一個v-node。 知道了這些數據結構的情況以后,我們可以更精確的知道某些操作的結果 1) 每次write操作結束后,當前文件的offset增加,如果這個操作導致當前的offset超出了文件長度,則i-node表中記錄的文件大小會被修改為改動后的大小。 2) 使用O_APPEND方式打開文件后,每次調用write函數時,當前文件的offset都會被設置為i-node表中的該文件大小,從而write函數只能在文件尾部追加。 3) lseek 函數只改變在file table中的當前文件offset,并不會產生io操作 注意file descriptor flag和file status flag的作用域差別,前者屬于某個單獨進程的單獨的file descriptor,后者則適用于任意進程中指向給定file table entry的所有descriptor。fcntl函數可以修改這兩種flag
1. 貌似和dive into python中的有一定的差異,可能是版本的關系(python 2.2 - 2.5) minidom.parse("binary.xml")得到的對象是binary.xml的整棵dom樹,它的第一個結點包含了DOCTYPE的相關信息,對于它的字節點的firstNode,貌似一般都是空的。
2. unicode 相關 string.encode() sys.getdefaultencoding() 指定.py文件編碼的方法: 在每個文件開頭加入編碼聲明 # -*- coding: UTF-8 -*-
3. python目錄的lib/site-packages/sitecustomize.py是一個特殊的腳本,Python會在啟動的時候導入它。
4. 搜索元素: getElementByTagName() 返回的是一個list
5. 元素屬性 attributes 是一個xml.dom.minidom.NameNodeMap實例,常用的方法如keys() values(),同時也有__getitem__方法,類似于dictionary
居然要軍訓兩星期后才搬去張江,殘念啊。。。 求到了個代理,總算能上外網,卻上不了TopCoder 在寢室百無聊賴ing...
算了,還是看會兒書吧
1. 幾個常用對象: os.system 執行命令 sys.stdin sys.stdout os.path.getsize 獲得文件大小 os.path.isdir os.mkdir os.listdir
2. walk()函數 很好用的一個函數 os.path.walk(rootdir, f, arg) rootdir是要訪問的目錄樹的根,f是用戶定義的函數,arg是調用f時用的一個參數。 對于每一個"walk"過程中遇到的目錄directory,設該目錄下的文件列表為filelist,walk函數會調用 f(arg, directory, filelist)
1. 交換x和y的值 [x, y] = [y, x]
2. zip()方法把幾個lists的第i個元素合成一個tuple,放在一個新的list中。 zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]
函數式編程相關
1. Mapping map() 方法對序列中的每個元素調用某個函數,返回新生成的結果序列。 有點類似于Ruby的Array.each do | element | >>> z = map(len, ["abc", "clounds", "rain"]) >>> z [3, 6, 4]
2. Filtering 過濾掉滿足條件的元素,類似與Array.reject do | element | >>> x = [5,12,-2,13] >>> y = filter(lambda z: z > 0, x) >>> y [5, 12, 13]
3. List Comprehension 來個復雜的例子 >>> y [[0, 2, 22], [1, 5, 12], [2, 3, 33]] >>> [a for b in y for a in b[1:]] [2, 22, 5, 12, 3, 33]
4. Reduction 先看示例 >>> x = reduce(lambda x,y: x+y, range(5)) >>> x 10 執行的順序是:首先調用函數處理range(5)前兩個值,0 + 1 = 1,然后返回的值1作為x,繼續與range(5)的第三個值(2,作為y)。 最后的結果是0+1+2+3+4的值 這個常用來代替for循環
|