(3.1)信號高級認識範例,服務器架構初步

一:信號高級認識範例

  //ps -eo pid,ppid,sid,tty,pgrp,comm,stat,cmd | grep -E 'bash|PID|nginx'

  //用kill 發送 USR1信號給進程

  //(1)執行信號處理函數被卡住了10秒,這個時候因爲流程回不到main(),所以main中的語句無法得到執行;

  //(2)在觸發SIGUSR1信號並因此sleep了10秒種期間,就算你多次觸發SIGUSR1信號,也不會重新執行SIGUSR1信號對應的信號處理函數,

   //而是會等待上一個SIGUSR1信號處理函數執行完畢才 第二次執行SIGUSR1信號處理函數;

   //換句話說:在信號處理函數被調用時,操作系統建立的新信號屏蔽字(sigprocmask()),自動包括了正在被遞送的信號,因此,

   //保證了在處理一個給定信號的時候,如果這個信號再次發生,那麼它會阻塞到對前一個信號處理結束爲止;

  //(3)不管你發送了多少次kill -usr1信號,在該信號處理函數執行期間,後續所有的SIGUSR1信號統統被歸結爲一次。

   //比如當前正在執行SIGUSR1信號的處理程序但沒有執行完畢,這個時候,你又發送來了5次SIGUSR1信號,那麼當SIGUSR1信號處理程序

   //執行完畢(解除阻塞),SIGUSR1信號的處理程序也只會被調用一次(而不會分別調用5次SIGUSR1信號的處理程序)

//kill -usr1,kill -usr2

  //(1)執行usr1信號處理程序,但是沒執行完時,是可以繼續進入到usr2信號處理程序裏邊去執行的,這個時候,

   //相當於usr2信號處理程序沒執行完畢,usr1信號處理程序也沒執行完畢;此時再發送usr1和usr2都不會有任何響應;

  //(2)既然是在執行usr1信號處理程序執行的時候來了usr2信號,導致又去執行了usr2信號處理程序,這就意味着,

   //只有usr2信號處理程序執行完畢,纔會返回到usr1信號處理程序,只有usr1信號處理程序執行完畢了,纔會最終返回到main函數主流程中去繼續執行;

 

  //思考:如果我希望在我處理SIGUSR1信號,執行usr1信號處理程序的時候,如果來了SIGUSR2信號,我想堵住(屏蔽住),

   //不想讓程序流程跳到SIGUSR2信號處理中去執行,可以做到的;我們後續會講解其他的如何屏蔽信號的方法;

 


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>


//信號處理函數
void sig_usr(int signo)
{         
    if(signo == SIGUSR1)
    {
        printf("收到了SIGUSR1信號,我休息10秒......!\n");
        sleep(10);
        printf("收到了SIGUSR1信號,我休息10秒完畢,甦醒了......!\n");
    }
    else if(signo == SIGUSR2)
    {
        printf("收到了SIGUSR2信號,我休息10秒......!\n");
        sleep(10);
        printf("收到了SIGUSR2信號,我休息10秒完畢,甦醒了......!\n");
    }
    else
    {
        printf("收到了未捕捉的信號%d!\n",signo);
    }
}

int main(int argc, char *const *argv)
{
    if(signal(SIGUSR1,sig_usr) == SIG_ERR)  //系統函數,參數1:是個信號,參數2:是個函數指針,代表一個針對該信號的捕捉處理函數
    {
        printf("無法捕捉SIGUSR1信號!\n");
    }
    if(signal(SIGUSR2,sig_usr) == SIG_ERR) 
    {
        printf("無法捕捉SIGUSR2信號!\n");
    }
    
    for(;;)
    {
        sleep(1); //休息1秒    
        printf("休息1秒~~~~!\n");
    }
    printf("再見!\n");
    return 0;
}


 

二:服務器架構初步

(2.1)目錄結構規劃(make編譯)

  //特別注意:不固安是目錄還是文件,文件名中一律不要帶空格,一律不要用中文,最好的方式:字母,數字,下劃線;

   //不要給自己找麻煩,遠離各種坑

  //主目錄名nginx

  //a)_include目錄:專門存放各種頭文件; 如果分散:#include "sfaf/sdafas/safd.h"

  //b)app目錄:放主應用程序.c(main()函數所在的文件)以及一些比較核心的文件;

   //b.1)link_obj:臨時目錄:會存放臨時的.o文件,這個目錄不手工創建,後續用makefile腳本來創建

   //b.2)dep:臨時目錄,會存放臨時的.d開頭的依賴文件,依賴文件能夠告知系統哪些相關的文件發生變化,需要重新編譯,後續用makefile腳本來創建

   //b.3)nginx.c:主文件,main()入口函數就放到這裏;

   //b.4)ngx_conf.c ,普通的源碼文件,跟主文件關係密切,又不值得單獨放在 一個目錄;

  //c)misc目錄:專門存放各種雜合性的不好歸類的1到多個.c文件;暫時爲空

  //d)net目錄:專門存放和網絡處理相關的1到多個.c文件,暫時爲空

  //e)proc目錄:專門存放和進程處理有古安的1到多個.c文件,暫時爲空

  //f)signal目錄:專門用於存放和信號處理 有古安的1到多個.c文件;

    //ngx_signal.c

 (2.2)編譯工具make的使用概述(編譯出可執行文件)

  //我們 要用傳統的 ,經過驗證沒有問題的方式來編譯我們的項目,最終生成可執行文件

  //每個.c生成一個.o,多個.c生成多個.o,最終這些.o被鏈接到一起,生成一個可執行文件

  //gcc -o nginx ng1.c

  //gcc -o nginx ng1.c ng2.c

  //a)我們要藉助make的命令來編譯:能夠編譯,鏈接。。。。最終生成可執行文件,大型項目一般都用make來搞;

  //b)make命令的工作原理,就去當前目錄讀取一個叫做makefile的文件(文本文件),根據這個makefile文件裏的

   //規則把咱們的源代碼編譯成可執行文件;咱們開發者的任務就是要把這個makefile文件寫出來;

   //這個makefile裏邊就定義了我們怎麼去編譯整個項目的編譯、鏈接規則

   //【實際上makefile文件就是一個我們編譯工程要用到的各種源文件等等的一個依賴關係描述】

  //有類似autotools自動生成makefile,這裏不講

  //c)makefile文件:文本文件,utf8編碼格式,沒有擴展名,一般放在根目錄下[也會根據需要放在子目錄](這裏nginx)

 

  //規劃一下makefile文件的編寫

  //a)nginx根目錄下我會放三個文件:

   //a.1)makefile:是咱們編譯項目的入口腳本,編譯項目從這裏開始,起總體控制作用;

   //a.2)config.mk:這是個配置腳本,被makefile文件包含;單獨分離出來是爲了應付一些可變的東西,所以,一般變動的東西都往這裏搞;

   //a.3)common.mk:是最重要最核心的編譯腳本,定義makefile的編譯規則,依賴規則等,通用性很強的一個腳本,

   //並且各個子目錄中都用到這個腳本來實現對應子目錄的.c文件的編譯;

 

  //b)每個子目錄下(app,signal)都有一個叫做makefile的文件,每個這個makefile文件,都會包含根目錄下的common.mk,

   //從而實現自己這個子目錄下的.c文件的編譯

  //現在的makefile不支持目錄中套子目錄,除非大家自己修改;

  //c)其他規劃,上邊講過;

   //app/link_obj臨時目錄,存放.o目標文件

   //app/dep:存放.d開頭的依賴關係文件;

 

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