進程環境

来源:http://www.cnblogs.com/cjaaron/archive/2017/07/10/7144865.html
-Advertisement-
Play Games

進程的啟動和終止 內核執行c程式時,利用exec函數調用一個特殊的啟動常式,該啟動常式叢內核中獲取命令行參數和環境變數值。 進程終止的情況 5種正常終止的情況: 3種異常終止情況 進程啟動和終止圖 atexit函數 一個進程最多可以登記32和函數(例如:signal函數),這些函數由exit函數自動 ...


進程的啟動和終止

內核執行c程式時,利用exec函數調用一個特殊的啟動常式,該啟動常式叢內核中獲取命令行參數和環境變數值。

進程終止的情況

5種正常終止的情況:

(1)從main函數返回;
(2)調用exit;
(3)調用_exit和_Exit函數;
(4)最後一個線程調用pthread_exit;
(5)最後一個線程從其啟動常式返回;  

3種異常終止情況

(1)調用abort;
(2)接到一個信號;
(3)最後一個線程對取消請求做出響應;

進程啟動和終止圖

進程啟動和終止圖

atexit函數

一個進程最多可以登記32和函數(例如:signal函數),這些函數由exit函數自動調用。在程式終止時調用這些函數,形成終止處理程式,來進行結束進程前的收尾工作。而exit函數通過atexit函數的登記記錄來判斷調用哪些函數。

exit函數

此函數由ISO C 定義,其操作包括處理終止處理程式,然後關閉所有標準I/O流。需要註意的是,它不會處理文件描述符、多進程(父子進程)以及作業控制。

_e(E)xit函數
ISO C 定義這個函數的目的是為進程提供一種無需運行終止處理程式或信號處理函數的方法而終止程式。但ISO C 對標準I/O流是否進行沖洗,這取決於操作系統的實現。在unix中,是不進行沖洗的。

exit和_e(E)ixt函數的狀態碼

無論進程怎樣結束,它都會在內核上執行同一段代碼(由進程啟動和退出圖可知)。這段代碼來關閉所有的文件描述符,釋放所有的存儲空間。

程式退出後,利用退出碼告知該進程的父進程。父進程通過wait或waitpid函數來完成該子進程的善後工作(獲取子進程相關信息 釋放子進程占用資源)。若父進程沒有處理子進程的退出狀態,則子進程變成僵死進程。相反的,若父進程在子進程前終止,則子進程變成孤兒進程。孤兒進程會由1號進程(init進程)接收,大致過程如下:

(1)進程終止時,內核逐個檢查所有活動的進程;
(2)分析查找該終止進程的子進程;
(3)將該進程的子進程的父進程ID改為1;

wait和waitpid函數

程式正常或異常終止時,內核都會向父進程發送SIGNAL信號。子進程終止是非同步事件,所以該信號也是非同步信號。而該信號一般會被父進程預設忽略。或者提供一個信號處理函數來善後。wait和waitpid函數就是其中的信號處理函數的一部分。

wait和waitpid函數區別如下:

(1)wait會阻塞調用者進程等待直至第一個終止的子進程到來;
(2)waitpid可以通過參數設置,來實現調用者進程不阻塞,或選擇要阻
塞等待的子進程;

這裡的調用者指的是父進程

環境表和環境變數

環境表結構圖

環境表結構

  • 每個程式都接收到一張環境表
  • 環境表也是一個字元指針數組
  • enrivon叫做環境指針
  • 指針數組叫做環境表
  • 各個指針指向的字元串叫做環境字元串

環境變數

  • unix內核並不檢查環境字元串,它們的解釋完全取決於各個應用進程
  • 通常在一個shell啟動文件中設置環境變數來控制shell的動作
  • 修改或者增加環境變數時,只能影響當前進程以及其後(之前的不行)生成和調用的任何子進程的環境,但不能影響其父進程的環境

和環境變數相關的函數如下:

#include<stdlib.h>
char *getenv(const char *name);
      返回值:指向與name關聯的value的指針;若未找到,返回NULL

int putenv(char *str);
                       返回值:若成功,返回0;若出錯,返回非0
                       
int setenv(const char *name, const char *value,
            int rewrite);
int unsetenv(const char *name);
                兩個函數返回值:若成功,返回0;若出錯,返回-1 

這些函數如何修改環境表的

環境表和環境字元串通常存放在記憶體空間的高地址處(頂部)。所以在修改它的值時,記憶體是不能繼續向高地址延伸;但又因為,它之下是各個棧幀,所以也不能向下延伸。如何修改它的值的過程如下:

(1)修改環境表

1)新value <= 舊value,直接覆蓋舊value的存儲空間
2)新value >= 舊value,調用malloc函數,在堆區開闢新的存儲空間,
將新value複製到這裡,再將這片存儲區首地址寫到環境表相應的位置處。

(2)新增環境表

1)新增一個環境變數,調用malloc函數開闢新的存儲空間,將原來的環
境表複製到該存儲區,其次再添加一個環境變數,然後在尾部賦值為NULL,
最後將environ指向該區域;
2)在 1)過程的基礎上,調用realloc函數,多次添加環境變數;

註意:以這種方式修改的環境變數只在當下程式運行時有效,當程式結束時,相應的存儲區被系統回收,這些修改就會失效。

記憶體存儲結構補充說明

記憶體管理結構圖

存儲空間結構

  • 未初始化數據段(block started by symbol):在程式開始執
    行之前,內核將此段中的數據初始化為0或空指針;
  • 棧:每次函數調用時,其返回地址以及調用者的環境信息(如某些機器寄存器的值)都存放在棧中;
  • 共用庫:只需在所有進程都可引用的存儲區中保存這種庫常式的一個副本;

存儲空間分配函數

#include<stdlib.h>
void *malloc(size_t size);
void *calloc(size_t nojy, size_t size);
void *realloc(void *ptr, size_t newsize);
         3個函數返回值:若成功,返回非空指針;若出錯,返回NULL
  • malloc函數:初始值不確定;底層通過調用sbrk函數實現;
  • calloc函數:初始值為0;
  • realloc函數:增加或減少以前分配區的長度;當增加長度時,可能將以前分配區的內容移到另一個足夠大的區域,以便在分配區末尾增加存儲區,而新增存儲區初始值不確定(例如:可變數組的使用);

註意:這些動態分配的函數一般在分配存儲空間時,會比要求的大。因為在開闢空間的前後部分存儲記錄管理信息。因此,在使用時,千萬不要越界訪問,以免造成不可預知的後果。

函數間跳轉策略

在c語言中,goto語句是不能跨函數跳轉的。尤其是在函數深層調用時的跳轉需求,在出錯處理的情況下非常有用。

#include<setjmp.h>
int setjmp(jmp_buf env);
          返回值:若直接調用,返回0;若從longjmp返回,返回非0
void longjmp(jmp_buf env, int val);

變數值回滾問題:自動變數和寄存器變數會存在回滾現象。利用volatile屬性來避免此類情況的發生。(在給變數賦值時,賦的值迴首先存儲在記憶體(存儲器變數)中,然後在由cpu取走,存儲在cpu的寄存器上(寄存器變數)。在做系統優化時,那些頻繁使用的變數,會直接存儲到寄存器中而不經過記憶體。)

寄存器變數會存在回滾現象的探究

在調用setjmp函數時,內核會把當前的棧頂指針保存在env變數中,所以在調用longjmp函數返回該位置時,全局變數、靜態變數、易失變數和自動變數如果在調用setjmp和longjmp函數之間它們的值被修改過,是不會回滾到setjmp函數調用之前的值(當然,編譯器將auto變數優化為寄存器變數除外)。因為,這些存儲器變數的值是存儲在記憶體相應的段中,回到原先棧頂狀態時,同樣訪問的還是原先的記憶體空間。

然而,對於寄存器變數來說,首先要明確一點:寄存器變數是用動態存儲的方式。意思是寄存器變數的值可能存在不同的寄存器中。如果在調setjmp和longjmp函數之間它們的值被修改過,這個值可能不會存到setjmp之前的對其賦值的寄存器中,而在調用longjmp函數後,又回到了調用setjmp函數時的狀態。這個時候再讀取寄存器變數的值時,讀到的是原先那個寄存器中存儲的值而不是修改過的那個寄存器中存儲的值,所以出現的回滾現象。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 轉載 http://blog.csdn.net/looksun/article/details/51445205 如一張表的數據如下: 需要根據gz列的值進行升序排序,但值為0的排在最後面,即最終結果如下圖: 具體 實現方法如下: 1.Order BY表達式 SELECT nian ,gz from ...
  • <mongodb在linux上的部署> 事實上redis安裝程式挺好,直接幫我們生成了服務,直接可以使用systemctl去啟動它,而mongodb在這方面沒有那麼智能,需要我們去編寫自己的服務腳本了,然後把它加到開機自啟動裡面就可以了,主要的過程分為以下幾個步驟: mongodb我安裝在了/roo ...
  • 以前在開發中需要用到帶錯誤處理的存儲過程,在網上找到瞭解決方案,現在整理在這,以備日後所需,時間長了原文已經找不到了,感謝為我提供幫助的兄弟。 1.創建錯誤日誌表 2.創建寫入錯誤日誌的存儲過程 3.創建列印錯誤信息的存儲過程 4.創建自己的存儲過程 ...
  • 在/usr/local/apache/conf/httpd.conf文件末位添加以下信息: ...
  • 上周日折騰了一次阿裡雲伺服器,被linux的網路問題折騰的夠嗆。在這裡簡單做個問題的概要記錄,以備忘。題目中說自己是小白,其實也不完全是小白,自己對一些linux的常用命令還是有所瞭解的,但是對於linux系統缺乏一個整體的把握和掌控能力,下麵簡單總結下上周日折騰的一些事情。 1,讓ssh登錄變的更 ...
  • 1. 準備工作: 準備一臺ubuntu機器,將boot.img複製到該機器上,下載必要的工具sudo apt-get install abootimggit clone https://github.com/anestisb/android-simg2img.gitcd android-simg2i ...
  • 本文所選的例子來自於《Advanced Bash-scripting Gudie》一書,譯者 楊春敏 黃毅 腳本運行結果 ...
  • Linux系統中文語言亂碼,是很多小伙伴在開始接觸Linux時經常遇到的問題,而且當我們將已在Wndows部署好的項目搬到Linux上運行時,Tomcat的輸出日誌中文全為亂碼(在Windows上正常),看著非常心塞,那麼我們應該怎麼解決呢? 系統中文亂碼 Tomcat輸出日誌中文亂碼 系統環境 C ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...