unix環境高級編程(中)-進程篇

目錄

前言

進程環境

進程控制

進程關係

信號

線程

線程控制

高級IO

進程間通訊

網絡間進程通訊:套接字

高級進程間通訊

前言

筆者將《unix環境高級編程》主要內容總結爲三篇:文件篇進程篇高級io和進程間通訊三大板塊。本文是unix環境高級編程系列文章第二篇:進程篇。該篇主要包括:node

進程環境

介紹進程相關的基本概念和使用環境:進程執行前的準備工做,進程如何終止,進程執行相關的環境變量表,進程執行時的內存空間佈局,內存如何分配linux

進程控制

主要介紹進程控制符,進程如何建立,如何執行,如何終止,等待終止ios

進程關係

主要介紹進程之間的關係,包括:進程組,會話,控制終端。以及unix底層的數據結構如何創建他們之間的關係算法

信號

主要介紹信號的概念,如何設置信號處理函數,收到信號致使系統中斷的調用以及能自動重啓的調用。而後介紹如何發送信號,如何屏蔽信號,以及致使的信號阻塞shell

線程

主要介紹線程的概念,線程標識符,線程如何建立,如何終止,等待終止狀態,設置自定義清理程序。而後對比了進程和線程相關概念和接口的對比。最後介紹線程的同步,包括:互斥量,讀寫鎖,條件變量編程

線程控制

主要介紹線程屬性,同步屬性:互斥量屬性,讀寫鎖屬性,條件變量屬性。而後介紹如何建立線程私有數據。最後介紹信號和fork對線程的影響數組

守護進程

主要說明守護進程的特徵,常見的系統守護進程,以及守護進程的編程規則。而後介紹處理守護進程的通用日誌架構,最後介紹守護進程的一些慣例緩存

一. 進程環境

1. 進程執行

進程執行從main函數開始,在這以前須要一些準備工做安全

  • 內核使用exec函數調用c程序
  • 執行c程序時,先調用一個特殊的啓動例程。
  • 可執行文件將此啓動例程指定爲程序的起始地址(gcc設置)
  • 啓動例程從內核取得命令行參數和環境變量
  • 上述工做準備就緒,開始執行main函數

2. 進程終止

2.1 正常終止

  • 從main返回
  • 調用exit:先執行一些清理工做(關閉io流等),而後進入內核
  • 調用_exit或_Exit:當即進入內核
  • 最後一個線程從其啓動例程返回
  • 最後一個線程調用pthread_exit

2.2 異常終止

  • 調用abort
  • 接到一個信號並終止
  • 最後一個線程堆取消請求作出相應

2.3 終止處理程序

  • 終止處理程序由exit自動調用,無需手動調用
  • 註冊終止處理程序的方法:atexit,參數爲函數地址
  • 註冊終止處理程序的最大數量:32
  • exit調用順序:與註冊順序相反,且不會去重,登記屢次就調用屢次

2.4 c程序啓動和終止流程圖

  • 內核使用程序執行的惟一方法是:調用一個exec函數
  • 用戶函數能夠直接調用_exit或者_Exit終止程序,此時直接進入內核,不會調用終止處理程序
  • 若是調用exit終止程序,它會先調用註冊的終止處理程序

3. 環境表

3.1 環境表內存佈局

每一個程序都會接收到一張環境表。環境表是一個字符指針數組,每一個指針包含一個以null結束的c字符串地址。全局變量environ表示該地址 bash

3.2 環境變量設置

  • 獲取環境變量指定變量值的函數:getenv
  • 設置環境變量的函數:
    • putenv:參數爲name=value的字符串形式,name存在則先刪除
    • setenv:參數是否存在根據rewrite決定
    • unsetenv:刪除某個環境變量

3.3 環境變量設置的底層實現

  • 環境變量表存放在進程存儲空間的頂部(棧之上),見下一小節的存儲空間佈局
  • 刪除一個環境變量很簡單,找到後刪除,後續指針依次往前移
  • 可是添加或者修改比較麻煩。由於它不能再向高地址(向上)擴展。同時也不能向下擴展到棧區。具體細節以下:
    • 修改現有的name:
      • 新value長度 < 舊的長度:覆蓋寫入
      • 新value長度 > 舊的長度:爲value分配新空間,將指針指向該空間
    • 新增一個name:先爲新name和value分配新空間
      • 第一次添加環境變量:先調用malloc爲新的指針表分配空間,再將數據放到表尾
      • 不是第一次添加:調用realloc擴展空間

4. 存儲空間佈局

c程序由下面幾部分組成:

  • 正文段:cpu執行的機器指令部分。正文段有可被共享,只讀的特性。

  • 數據段(初始化數據段):包含程序中明確賦初始值的變量

  • 非初始化數據段(bss段):函數外申明的未初始化數據

  • 棧:局部變量,函數調用所需信息。每次調用時的返回地址等信息都存放在棧。棧從高地址向低地址方向增加

  • 堆:動態存儲分配。位於非初始化數據段和棧之間

    使用size命令能夠查看各個部分的大小

5. 存儲器分配

5.1 內存空間動態分配的函數

  • malloc:分配製度字節數的存儲區,初始值不肯定
  • calloc:指定數量,指定長度的對象分配空間,每一位初始化爲0
  • realloc:更改之前分配的長度
  • 最終都調用sbrk內核函數,分配後不釋放會致使內存泄漏

5.2 其餘替代的存儲器分配程序

分配器出錯難於追蹤,不少替代的分配器在分配或釋放時,會進行附加的操做,以便追蹤問題

  • libmalloc:
  • vmalloc:
  • 快速適配quick-fit: 改善了標準malloc的最佳適配或首次適配分配策略
  • alloca:在棧上分配空間,而不是堆上。

二. 進程控制

1. 基本概念

1.1 進程標識符

  • 每一個進程都有一個非負整數表示的惟一進程ID
  • id爲0的進程一般是調度進程(交換進程,系統進程),是內核的一部分。
  • id爲1的進程一般是init進程,是普通進程。以超級用戶運行。文件爲/sbin/init。負責在自舉內核後啓動unix系統。
  • id爲2的進程一般爲頁守護進程,負責支持虛擬存儲系統的分頁操做
  • 除了進程id,每一個進程還有其餘標識,調用getpid能夠得到

1.2 進程控制原語

  • 建立新進程:fork
  • 執行新進程:exec
  • 處理終止:exit
  • 等待終止:wait

2. 建立進程

2.1 fork函數

  • 一個現有進程調用fork能夠建立一個新進程,稱爲子進程
  • fork函數調用一次,返回兩次:子進程返回0,父進程返回子進程id
  • 子進程是父進程的副本。正文段由父子共享,可是數據空間,堆,棧各自維護
  • 因爲fork以後經常跟隨exec,如今不少實現並非執行真正的複製,而是使用「寫時複製」技術(COW):父子共享訪問這些空間,且設爲只讀,若是試圖修改,就只複製修改的部分
  • fork以後的執行順序是不肯定的,取決於內核使用的調度算法
  • fork的兩個應用場景:
    • 網絡服務:父進程接收客戶端請求,請求來時fork出子進程處理,父進程繼續等待請求
    • shell:一個進程執行不一樣的程序

2.2 vfork函數

功能相似與fork,區別以下:

  • 區別一:vfork建立的子進程並不將父進程的地址空間徹底複製到子進程中,子進程調用exec時,它在父進程的空間中運行,以提升效率(比前面說的COW效率更高)
  • 區別二:保證子進程先執行,調用exec或exit以後父進程纔可能被調度

3. 終止進程

前面介紹了終止進程的8中狀況。無論哪一種方式,都有一些特性:

  • 最後都會執行內核中的同一段代碼:爲進程關閉全部打開的文件描述符,釋放使用的內存。
  • 都但願終止進程可以通知父進程它是如何終止的:
    • 正常終止:進程將退出狀態做爲參數傳給函數
    • 異常終止:內核產生一個指示其終止緣由的終止狀態,_exit將終止狀態轉化爲退出狀態
  • 父進程都能經過wait或waitpid取得終止狀態
  • 當一個進程停止時,內核就向其父進程發送SIGCHLD信號(異步信號)
  • 父進程能夠選擇忽略或提供信號處理程序
  • 若是父進程在子進程以前終止,子進程的父進程都變爲init進程。(每一個進程停止前都作檢查)

4. 等待停止

4.1 wait/waitpid函數

4.1.1 調用wait的進程可能發生什麼狀況:

  • 若是全部子進程都還在運行,則阻塞
  • 若是一個子進程已經終止,正等待父進程獲取終止狀態,則取得狀態馬上返回
  • 若是沒有任何子進程,則出錯返回
  • 若是進程因爲收到SIGCHLD而調用wait,可能獲得返回。任意時刻調用,可能會阻塞

4.1.2 區別

  • wait:使調用者阻塞
  • waitpid:選項可設置爲阻塞或不阻塞,容許指定等待的子進程

4.1.3 參數

  • 不爲空,則將狀態信息保存在參數中返回
  • 終止狀態宏:存放在<sys/wait.h>
    • WIFEXITED:正常終止
    • WIFSIGNALED:異常終止
    • WIFSTOPPED:暫停子進程
    • WIFCONTINUED:暫停以後繼續

4.2 waitid函數

  • 功能與waitpid類似,不過使用單獨的參數(idtype)表示要等待的子線程類型

4.3 wait3和wait4

  • 功能比前面幾個wait函數多一項,與參數rusage有關
  • 要求返回終止進程及子進程使用的資源彙總,包括用戶cpu時間總量,系統cpu時間總量,頁面出錯次數,接收到的信號次數。

5. 競爭條件

  • 多個進程企圖對共享數據進行某些處理,而最後的結果取決與容許的順序,則認爲發生了競爭條件
  • 爲了不競爭條件,須要使用信號或進程間通訊機制

6. 進程執行

6.1 exec說明

  • 進程調用exec以執行另外一個程序
  • 調用exec時,該進程執行程序徹底替換爲新程序,新程序從main開始執行
  • 調用exec並不建立新的進程,因此先後進程id不變
  • exec用一個全新的程序替換當前進程的正文,數據,堆和棧

6.2 各函數說明

  • 前四個取路徑名做爲參數,後兩個取文件名作爲參數
  • filename中包含/符號,則將其視爲路徑名,不然就在PATH中搜索
  • l表明list,v表示vector。l要求每一個參數單獨傳入,v要求傳入參數數組
  • 以e結尾的函數能夠傳遞環境字符串指針

7. 解釋器文件

  • 在文本文件第一行添加 #! pathname,好比 #! /bin/bash
  • 這種文件由內核做爲exec系統調用的一部分來完成
  • exec函數並不執行該文件,而是第一行pathname指定的文件

8. system函數

9. 進程會計

  • 啓用該功能時,進程結束後會寫一個會計記錄:命令,cpu時間,啓動時間等
  • 存放位置:/var/account
  • 頭文件:<sys/acct.h>

三. 進程關係

1. 進程組

  • 每一個進程除了有進程id外,還屬於一個進程組(一個或多個進程的集合)
  • 進程組與同一個做業相關聯,能夠接收來自同一終端的各類信號
  • 進程組有一個惟一的id,相關函數:getpgrp,getpgid
  • 每一個進程組均可以有一個組長進程(進程組id=進程id)
  • 加入或建立一個新的進程組:setpgid,setsid
  • 一個進程只能爲它或它本身設置進程組ID,子進程調用exec以後就不能改變它都進程組id

2. 會話

  • 會話是一個或多個進程組的集合
  • 建立會話:setsid

3. 控制終端

  • 一個會話能夠有一個控制終端
  • 一般是登錄的終端設備或僞終端設備
  • 一個會話中的幾個進程組能夠分爲一個前臺進程組和一個或多個後臺進程組

4. 進程,進程組,會話,控制終端的實現

  • 每一個會話都分配一個session結構
    • s_count:進程組數。減爲0時,可釋放該結構
    • s_leader:指向會話首進程指針,用proc結構表示
    • s_ttyvp:指向終端控制v-node的指針
    • s_ttyp:指向終端控制tty結構的指針
    • s_sid:會話id
  • 每一個終端或僞終端設備都分配一個tty結構
    • t_session:指向會話(互相指向)
    • t_pgrp:指向前臺進程組的pgrp結構。利用此發送信號到前臺進程組
    • t_termios:包含終端有關的信息
    • t_winsize:包含終端窗口當前尺寸的winsize結構
  • 前臺進程組pgrp,包含特定進程組信息
    • pg_id:進程組id
    • pg_session:指向此進程組所屬的session
    • pg_members:進程組成員列表指針
  • 每一個進程proc
    • p_pid:進程id
    • p_pptr:指向父進程的指針
    • p_pgrp:指向所屬的進程組指針

四. 信號

1. 信號的概念

  • 信號是軟件中斷,提供了一種處理異步事件的方法
  • 每一個信號都有一個名字,以SIG開頭。在頭文件<signal.h>中定義爲正整數的宏
  • 產生信號的事件對進程而言是隨機出現的,進程必須告訴內核調用什麼信號處理函數或者忽略
  • 信號產生的一些舉例
    • 硬件異常:如除0錯誤,無效內存引用
    • 進程調用kill(2):將信號發送給另外一個進程或進程組,是否終止看信號類型,以及是否捕獲該信號
    • 進程調用kill(1):將信號發送給另外一個進程,是否終止看信號類型,以及是否捕獲該信號
    • 檢測到某種軟件條件已經發生,發送信號通知其餘進程
  • 一些常見的信號
    • SIGABORT:異常終止
    • SIGALRM:超時
    • SIGBUS:硬件故障
    • SIGCHLD:子進程狀態改變
    • SIGEMT:硬件故障
    • SIGINT:終端中斷符
    • SIGIO:異步IO
    • SIGKILL:終止
    • SIGPOLL:可輪詢事件
    • SIGSEGV:無效內存引用
  • 信號的處理:
    • 執行一個程序時,一般全部信號的狀態都是系統默認
    • 當調用exec時,將原先設置爲要捕捉的信號都修改成默認(信號函數地址在新的進程可能無效)
    • shell中執行後臺進程時,會忽略中斷和退出信號
    • fork建立子進程時,複製父進程的存儲映像,子進程會繼承父進程的信號處理方式

2. signal函數

  • 做用:設置信號處理函數
  • 函數須要兩個參數,返回一個函數指針,該指針指向的函數無返回值,返回的函數須要一個整形參數
  • 第一個參數signo是整數,第二個參數是函數指針,該指針須要一個整形參數,無返回值

3. 中斷的系統調用

  • 進程執行低速的系統調用時,若是捕獲到信號,系統調用被中斷再也不繼續,返回出錯。以便喚醒被阻塞的系統調用
  • 表明必須顯示處理這種出錯
  • 爲了幫助應用程序每次手動處理這個狀況,引入了系統調用的自動重啓
  • 自動重啓的系統調用包括
    • ioctl
    • read
    • readv
    • write
    • writev
    • wait
    • waitpid

4. 信號術語

  • 信號產生:引起信號的事件發生時
  • 信號來源:硬件異常,軟件條件,終端信號,kill函數等
  • 信號遞送:進程表中設置一個某種形式的標誌
  • 信號未決:信號產生與信號遞送之間的時間間隔
  • 信號阻塞:設置爲阻塞時,將保持信號未決狀態(傳遞被推遲,直到解除阻塞爲止)。函數sigpending決定哪些信號設置爲阻塞並處於未決狀態。
  • 信號屏蔽:進程的信號屏蔽字,阻塞送到該進程的信號集:sigprocmask能夠查看和更改信號屏蔽字
  • 信號集:sigset_t保存

5. kill和raise

  • kill:將信號發給進程或進程組
    • pid > 0: 信號發送給進程id爲pid的進程
    • pid = 0:信號發送給與本身同處一個進程組的全部進程,並且有發送信號的權限
    • pid < 0:信號發送給與其餘進程組id等於pid絕對值,並且有發送信號的權限。
    • pid = -1:發送信給號有權限發送的全部進程
  • raise:容許進程向自身發送信號
  • raise(signo) = kill(getpid(), signo)

6. alarm和pause

alarm

  • alarm:設置定時器,定時器超時時,產生SIGALRM信號。若是不忽略或不捕捉則中止調用該函數的進程
  • 參數:秒。
  • 說明:
    • 信號由內核產生,因爲進程調度的延遲,獲得控制和處理還需一些時間
    • 一個進程只能有一個鬧鐘,第二次設置會覆蓋第一次,返回第一次剩餘時間。若是參數爲0即取消鬧鐘

pause

  • 使調用進程掛起,直至捕捉到一個信號
  • 只有執行了一個信號處理程序並返回,pause返回-1

7. 信號集

  • 概念:表示多個信號的數據類型
  • 相關函數:

8. 信號屏蔽字

  • 概念:規定了應該被阻塞不能傳遞給該進程的信號集,以保護不被信號中斷的代碼
  • 做用域:僅爲單線程定義的
  • 函數:
  • how參數:
    • SIG_BLOCK:當前信號屏蔽字和set的並集。添加信號屏蔽字
    • SIG_UNBLOCK:當前信號屏蔽字和set補集的交集。解除信號屏蔽字
    • SIG_SETMASK:信號屏蔽字被set集合替代

9. sigspending

  • 做用:返回進程中被阻塞的信號集
  • 原型:

10. sigaction

  • 做用:檢查或修改指定信號相關聯的處理動做。替代早期的signal函數
  • 原型:
  • 參數:
    • act:若非空,爲要修改的動做
    • oact:若非空,返回上一個動做

11. sigsuspend

  • 做用:恢復進程信號屏蔽字,使其休眠
  • 原型:
  • 參數:sigmask
    • 將進程的信號屏蔽字設置爲由sigmask指定的值
  • 說明
    • 將進程的信號屏蔽字設置爲由sigmask指定的值,在捕捉到一個信號或發生一個會終止該進程的信號前,該進程被掛起。若是捕捉到信號並且從函數返回,則suspend返回,且將信號屏蔽字還原

12. abort

  • 做用:使異常程序停止
  • 說明:發生SIGABORT信號給進程,進程不能忽略此信號。信號處理函數執行清理操做,具體由實現來決定,包括:清洗輸出流,刪除臨時文件,關閉流等

13. sleep

  • 做用:是調用進程被掛起
  • 原型:
  • 被喚醒的狀況
    • 時間超過參數的時間
    • 進程捕獲到一個信號,並從信號處理函數返回

五. 線程

1. 線程的概念

  • 進程中獨自處理任務的一個控制單元
  • 線程包含的信息:
    • 進程的全部資源,包括程序文本,程序全局內存,堆內存,棧,文件描述符
    • 自身的信息:線程id,寄存器值,棧,調度優先級和策略,信號屏蔽字,errorno變量以及線程私有數據
  • 多線程的好處:
    • 每種事件類型分配單獨的線程,能簡化異步事件代碼。每一個線程內部是同步的。
    • 要實現內存和文件描述符的共享,使用多進程是很複雜的。多線程天生具有該功能
    • 任務並行,提升吞吐率
    • 界面交互程序,使用多線程能夠改善響應時間
  • 說明:即便在單核cpu上也是能夠很好的使用多線程,並非只有多核cpu才能使用多線程

2. 線程標識

  • 線程id:線程的惟一標識
  • 表示:pthread_t數據類型,各個操做系統有不一樣的具體實現,linux下爲無符號的長整形
  • 線程id比較:不能用簡單的數值比較,使用pthread_equal函數
  • 獲取ID:pthread_self函數

3. 線程建立

  • 函數:pthread_create
  • 原型:
  • 參數:
    • tidp:返回的建立線程的線程id
    • attr:線程屬性,設置爲NULL表示使用默認線程屬性
    • start_rin:線程執行入口函數
    • arg:線程執行函數的參數,多個參數必須以結構體的方式傳入
  • 執行順序:建立時並不能保證哪一個線程會先執行

4. 線程停止

4.1 線程停止的狀況

  • 進程中任意一個線程調用exit,_exit或_Exit中的任意一個都會使整個進程停止
  • 單個線程能夠經過如下方式退出,而不用結束整個進程
    • 線程從啓動例程中返回,返回值爲線程退出碼
    • 線程被同一進程的其餘線程取消:pthread_cancel
    • 調用pthread_exit函數,參數爲返回值

4.2 獲取線程停止狀態

  • 原型:
  • 說明:調用該函數的線程將阻塞,直到第一個參數指定的線程停止
  • 參數:
    • thread:
    • rval_ptr:
      • 若是線程處理函數經過return返回,該值爲return的值
      • 若是線程經過pthread_exit返回,該值爲返回的值
      • 若是線程被取消,該值爲PTHRREAD_CANCELED
      • 若是該值本身設置爲NULL,表示不想獲取退出狀態

4.3 設置線程清理處理程序

5. 進程原語和線程原語的對比

6. 線程同步

6.1 互斥量

概述

  • 本質是一把鎖。訪問共享資源前加鎖,訪問完成後釋放鎖。
  • 加鎖後,其餘線程想訪問將會被阻塞直到鎖被釋放
  • 鎖被釋放時,全部被阻塞線程將變成可運行狀態,但只有一個線程能搶到鎖,其餘線程再次被阻塞

相關接口

  • 數據類型:pthread_mutex_t
  • 初始化:
    • 靜態分配的互斥量:置爲常量PTHREAD_MUTEX_INITIALIZER
    • 動態分配的互斥量:pthread_mutex_init
  • 釋放:
    • pthread_mutex_destroy
  • 加鎖和釋放鎖
  • 注意事項:死鎖

6.2 讀寫鎖

概述

  • 也叫共享-獨佔鎖
  • 運行比互斥量更高的並行性
  • 三種狀態:
    • 讀模式加鎖狀態:可多個線程佔用
    • 寫模式加鎖狀態:僅一個線程佔用
    • 不加鎖狀態

相關接口

  • 數據類型:pthread_rwlock_t
  • 初始化和釋放:
  • 加鎖和解鎖:

6.3 條件變量

概述

  • 給多個線程提供了一個匯合的場所
  • 與互斥量一塊兒使用時,運行線程以無競爭的方式等待特定條件發生
  • 條件變量自己由互斥量保護

相關接口

  • 數據類型:pthread_cond_t
  • 初始化:
    • 靜態分配的變量:PTHREAD_COND_INITIALIZER
    • 動態分配的變量:pthread_cond_init
  • 加鎖和釋放:
  • 喚醒等待條件的線程

六. 線程控制

1. 線程屬性

  • 數據結構:pthread_attr_t,結構體內容不可見
  • 屬性包括:
    • detashstate:線程的分離狀態屬性
    • guardsize:線程棧末尾的警惕緩衝區大小
    • stackaddr:線程棧最低地址
    • stacksize:線程棧大小
    • 併發度:控制着用戶線程能夠映射的內核線程或進程數目
  • 其餘屬性:不在pthread_attr_t中,影響調用pthread_cancel時的行爲
    • 可取消狀態:pthread_setcancelstate
      • PTHREAD_CANCEL_ENABLE
        • PTHREAD_CANCEL_DISABLE
    • 可取消類型
  • 初始化與釋放:

2. 同步屬性

2.1 互斥量屬性

  • 數據結構:pthread_mutexattr_t
  • 初始化和釋放:
  • 屬性參數
    • 進程共享屬性
      • PTHREAD_PROCESS_PRIVATE:默認屬性,多個線程可訪問同一個同步對象
      • PTHREAD_PROCESS_SHARED:多個進程共享的內存區域分配的互斥量能夠用於進程同步
    • 類型屬性
      • PTHREAD_MUTEX_NORMAL:正常屬性,不作特殊的錯誤檢查或死鎖檢查
      • PTHREAD_MUTEX_ERRORCHECK:提供錯誤檢查
      • PTHREAD_MUTEX_RECURSIVE:運行進行屢次加鎖
      • PTHREAD_MUTEX_DEFAULT:請求默認語義,能夠映射爲其餘類型

2.2 讀寫鎖屬性

  • 數據結構:pthread_rwlockattr_t
  • 初始化和釋放:
  • 屬性參數:
    • 進程共享屬性:同互斥量屬性

2.3 條件變量屬性

  • 數據結構:pthread_condattr_t
  • 初始化和釋放:
  • 屬性參數:
    • 進程共享屬性:同互斥量屬性

3. 線程安全

  • 線程安全:一個函數在同一時間能夠被多個線程安全的調用。或者,一個函數對多個線程來講是可重入的。

4. 線程私有數據

4.1 線程私有數據的分配-建立鍵

  • 建立與該數據關聯的鍵,用於對線程私有數據對訪問權
    • 第二個參數:爲該鍵關聯對析構函數,析構函數參數爲地址
  • 該鍵能夠被進程中對全部線程使用,但每一個線程把這個鍵與不一樣的私有數據地址進行關聯
  • 線程能夠爲線程私有數據分配多個鍵
  • 安全的建立鍵:調用pthread_once函數,將建立鍵的函數做爲參數傳入

4.2 鍵與線程私有數據的關聯

4.2 鍵與線程私有數據的取消

5. 線程與信號

  • 每一個信號有本身的信號屏蔽字,可是信號處理程序是共享的。意味着單個信號修改了某個信號相關的處理行爲,其餘線程必須共享這個行爲
  • 設置線程信號屏蔽字:pthread_sigmask
  • 等待信號發生:sigwait
  • 發生信號到線程:pthread_kill
  • linux線程是以獨立進程實現的。所以遇到信號時行爲與其餘系統不一樣

6. 線程與fork

  • 線程調用fork時,爲子進程建立整個進程地址空間的副本,繼承父進程的互斥量,讀寫鎖和條件變量的狀態
  • fork返回後,若是不是立馬調用exec,須要清理鎖狀態:pthread_atfork函數能夠作到
  • 子進程內部只包含一個線程副本:父進程中調用fork函數的線程

7. 線程與io

  • pread和pwrite做爲原子操做,能夠解決併發線程對同一文件進行讀寫操做對問題

七. 守護進程

1. 特徵

  • 守護進程沒有終端,在後臺運行的一種生存期較長的進程
  • 大多數都以超級用戶特權運行
  • 大多數守護進程的父進程是init進程

2. 系統守護進程

  • keventd守護進程: 在內核中運行計劃執行函數提供進程上下文
  • kapmd守護進程:爲計算機高級電源管理提供支持
  • kswapd守護進程:頁面調出守護進程,將髒頁低速寫到磁盤以回收,用於支持虛擬子系統
  • bdflush和kupdated:將高速緩存到數據沖洗到磁盤上
  • portmap:端口映射守護進程
  • syslogd:記錄日誌消息
  • inetd,xinetd:監聽系統網絡接口,接收網絡服務請求
  • nfsd,lockd,rpciod:提供網絡文件系統的支持
  • crond:定時任務

3. 編程規則

  • 調用umask將文件模式建立屏蔽字設置爲0
  • 調用fork,使父進程退出
  • 調用setsid,建立新的會話,使得新進程:
    • 成爲新會話的首進程
    • 成爲一個新進程組的組長進程
    • 沒有控制終端
  • 將當前工做目錄更改成根目錄
  • 關閉再也不須要的文件描述符
  • 某些守護進程打開/dev/null,使其具備文件描述符0,1,2

4. 出錯記錄

4.1 守護進程日誌的來源

  • 內核例程調用log函數,任何一個用戶進程經過打開而後讀/dev/klog設備就能夠讀取這些信息
  • 大多數守護進程調用syslog(3)函數產生日誌消息,這些消息發生至/dev/log(udp網絡編程方式發送)
  • 在此主機上的用戶進程,或經過網絡鏈接的其餘主機的用戶進程可將日誌消息發至UDP端口514

4.2 守護進程日誌處理

  • syslogd守護進程讀取這三種格式的日誌文件。而後根據配置文件/etc/syslog.conf,決定將不一樣類型的日誌送往何處

4.2 日誌

5. 守護進程的慣例

  • 若守護進程使用鎖文件(爲了建立惟一守護進程),那麼該文件一般放在/var/run/name.pid中
  • 若守護進程支持配置選項,配置文件一般放在/etc/name.conf
  • 守護進程能夠用命令行啓動,但一般是系統初始化腳本之一(/etc/rc*或/etc/init.d/*啓動。要使守護進程重啓,可在/etc/inittab中爲該守護進程添加_respawn記錄項
  • 配置文件啓動後再也不會被讀取,爲避免修改配置文件重啓,某些守護進程會捕捉SIGHUP信號,而後重讀配置文件
相關文章
相關標籤/搜索