一:信號功能實戰
//signal():註冊信號處理程序的函數;
//商業軟件中,不用signal(),而要用sigaction();
二:nginx中創建worker子進程
//官方nginx ,一個master進程,創建了多個worker子進程;
// master process ./nginx
// worker process
//(i)ngx_master_process_cycle() //創建子進程等一系列動作
//(i) ngx_setproctitle() //設置進程標題
//(i) ngx_start_worker_processes() //創建worker子進程
//(i) for (i = 0; i < threadnums; i++) //master進程在走這個循環,來創建若干個子進程
//(i) ngx_spawn_process(i,"worker process");
//(i) pid = fork(); //分叉,從原來的一個master進程(一個叉),分成兩個叉(原有的master進程,以及一個新fork()出來的worker進程
//(i) //只有子進程這個分叉纔會執行ngx_worker_process_cycle()
//(i) ngx_worker_process_cycle(inum,pprocname); //子進程分叉
//(i) ngx_worker_process_init();
//(i) sigemptyset(&set);
//(i) sigprocmask(SIG_SETMASK, &set, NULL); //允許接收所有信號
//(i) ngx_setproctitle(pprocname); //重新爲子進程設置標題爲worker process
//(i) for ( ;; ) {}. .... //子進程開始在這裏不斷的死循環
//(i) sigemptyset(&set);
//(i) for ( ;; ) {}. //父進程[master進程]會一直在這裏循環
//kill -9 -1344 ,用負號 -組id,可以殺死一組進程
(2.1)sigsuspend()函數講解
//a)根據給定的參數設置新的mask 並 阻塞當前進程【因爲是個空集,所以不阻塞任何信號】
//b)此時,一旦收到信號,便恢復原先的信號屏蔽【我們原來的mask在上邊設置的,阻塞了多達10個信號,從而保證我下邊的執行流程不會再次被其他信號截斷】
//c)調用該信號對應的信號處理函數
//d)信號處理函數返回後,sigsuspend返回,使程序流程繼續往下走
三:日誌輸出重要信息談
(3.1)換行回車進一步示意
//\r:回車符,把打印【輸出】信息的爲止定位到本行開頭
//\n:換行符,把輸出爲止移動到下一行
//一般把光標移動到下一行的開頭,\r\n
//a)比如windows下,每行結尾 \r\n
//b)類Unix,每行結尾就只有\n
//c)Mac蘋果系統,每行結尾只有\r
//結論:統一用\n就行了
(3.2)printf()函數不加\n無法及時輸出的解釋
//printf末尾不加\n就無法及時的將信息顯示到屏幕 ,這是因爲 行緩存[windows上一般沒有,類Unix上纔有]
//需要輸出的數據不直接顯示到終端,而是首先緩存到某個地方,當遇到行刷新表指或者該緩存已滿的情況下,菜會把緩存的數據顯示到終端設備;
//ANSI C中定義\n認爲是行刷新標記,所以,printf函數沒有帶\n是不會自動刷新輸出流,直至行緩存被填滿才顯示到屏幕上;
//所以大家用printf的時候,注意末尾要用\n;
//或者:fflush(stdout);
//或者:setvbuf(stdout,NULL,_IONBF,0); //這個函數. 直接將printf緩衝區禁止, printf就直接輸出了。
//標準I/O函數,後邊還會講到
四:write()函數思考
//多個進程同時去寫一個文件,比如5個進程同時往日誌文件中寫,會不會造成日誌文件混亂。
//多個進程同時寫 一個日誌文件,我們看到輸出結果並不混亂,是有序的;我們的日誌代碼應對多進程往日誌文件中寫時沒有問題;
//《Unix環境高級編程 第三版》第三章:文件I/O裏邊的3.10-3.12,涉及到了文件共享、原子操作以及函數dup,dup2的講解;
//第八章:進程控制 裏庇安的8.3,涉及到了fork()函數;
//a)多個進程寫一個文件,可能會出現數據覆蓋,混亂等情況
//b)ngx_log.fd = open((const char *)plogname,O_WRONLY|O_APPEND|O_CREAT,0644);
//O_APPEND這個標記能夠保證多個進程操作同一個文件時不會相互覆蓋;
//c)內核wirte()寫入時是原子操作;
//d)父進程fork()子進程是親緣關係。是會共享文件表項,
//--------------關於write()寫的安全問題,是否數據成功被寫到磁盤;
//e)write()調用返回時,內核已經將應用程序緩衝區所提供的數據放到了內核緩衝區,但是無法保證數據已經寫出到其預定的目的地【磁盤 】;
//的確,因爲write()調用速度極快,可能沒有時間完成該項目的工作【實際寫磁盤】,所以這個wirte()調用不等價於數據在內核緩衝區和磁盤之間的數據交換
//f)打開文件使用了 O_APPEND,多個進程寫日誌用write()來寫;
//(4.1)掉電導致write()的數據丟失破解法
//a)直接I/O:直接訪問物理磁盤:
//O_DIRECT:繞過內核緩衝區。用posix_memalign
//b)open文件時用O_SYNC選項:
//同步選項【把數據直接同步到磁盤】,只針對write函數有效,使每次write()操作等待物理I/O操作的完成;
//具體說,就是將寫入內核緩衝區的數據立即寫入磁盤,將掉電等問題造成的損失減到最小;
//每次寫磁盤數據,務必要大塊大塊寫,一般都512-4k 4k的寫;不要每次只寫幾個字節,否則會被抽死;************
//c)緩存同步:儘量保證緩存數據和寫道磁盤上的數據一致;
//sync(void):將所有修改過的塊緩衝區排入寫隊列;然後返回,並不等待實際寫磁盤操作結束,數據是否寫入磁盤並沒有保證;
//fsync(int fd):將fd對應的文件的塊緩衝區立即寫入磁盤,並等待實際寫磁盤操作結束返回;*******************************
//fdatasync(int fd):類似於fsync,但隻影響文件的數據部分。而fsync不一樣,fsync除數據外,還會同步更新文件屬性;
//write(4k),1000次之後,一直到把這個write完整[假設整個文件4M]。
//fsync(fd) ,1次fsync [多次write,每次write建議都4k,然後調用一次fsync(),這纔是用fsync()的正確用法****************]
五:標準IO庫
//fopen,fclose
//fread,fwrite
//fflush
//fseek
//fgetc,getc,getchar
//fputc,put,putchar
//fgets,gets
//printf,fprintf,sprintf
//scanf,fscan,sscanf
//fwrite和write有啥區別;
//fwrite()是標準I/O庫一般在stdio.h文件
//write():系統調用;
//有一句話:所有系統調用都是原子性的