(3.4)信號,子進程實戰,文件IO詳談

一:信號功能實戰

    //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():系統調用;

 

    //有一句話:所有系統調用都是原子性的

 

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