Linux系統編程--2(環境變量,進程控制)

環境變量

環境變量

是指在操作系統中用來指定操作系統運行環境的一些參數
每個人用電腦的習慣不一樣,比如一般把文件放到磁盤,怎么管理文件,用什么編譯器,所以,環境變量就是根據每個人使用操作系統的習慣來規定一些參數

具體特征

  1. 字符串(本質)
  2. 有統一的格式:名=值[:值]
  3. 值用來描述進程環境信息

存儲形式:

與命令行參數類似。char*[]數組,數組名 environ,內部存儲字符串,NULL 作為哨兵結尾。

使用形式:

與命令行參數類似。

加載位置:

與命令行參數類似。位于用戶區,高于 stack 的起始位置。 引入環境變量表:須聲明環境變量。externchar**environ;

在這里插入圖片描述

打印當前進程的所有環境變量

在這里插入圖片描述

在這里插入圖片描述

常見環境變量

按照慣例,環境變量字符串都是 name=value 這樣的形式,大多數 name 由大寫字母加下劃線組成,一般把 name 的部分叫做環境變量,value 的部分則是環境變量的值。

PATH

可執行文件的搜索路徑。ls 命令也是一個程序,執行它不需要提供完整的路徑名/bin/ls,然而通常我們執行當 前目錄下的程序 a.out 卻需要提供完整的路徑名./a.out,這是因為 PATH 環境變量的值里面包含了 ls 命令所在的目錄 /bin,卻不包含 a.out 所在的目錄。PATH 環境變量的值可以包含多個目錄,用:號隔開。在 Shell 中用 echo 命令可以 查看這個環境變量的值:

$echo$PATH

在這里插入圖片描述
shell解析器按照PATH環境變量中已經設定好的目錄,一個目錄一個目錄找

SHELL

當前 Shell,它的值通常是/bin/bash。

TERM

當前終端類型,在圖形界面終端下它的值通常是 xterm,終端類型決定了一些程序的輸出顯示方式,比如圖形 界面終端可以顯示漢字,而字符終端一般不行。

LANG

語言和 locale,決定了字符編碼以及時間、貨幣等信息的顯示格式。

HOME

當前用戶主目錄的路徑,很多程序需要在主目錄下保存配置文件,使得每個用戶在運行該程序時都有自己的一套配置。

環境變量的相關函數

getenv 函數

在這里插入圖片描述

獲取環境變量值

chargetenv(constcharname); 成功:返回環境變量的值;失敗:NULL(name 不存在)

setenv 函數

在這里插入圖片描述

設置環境變量的值

intsetenv(constcharname,constcharvalue,intoverwrite); 成功:0;失敗:-1
參數 overwrite 取值: 1:覆蓋原環境變量 0:不覆蓋。(該參數常用于設置新環境變量,如:ABC=haha-day-night)

unsetenv 函數

在這里插入圖片描述

刪除環境變量 name 的定義

intunsetenv(constchar*name); 成功:0;失敗:-1
注意事項:name 不存在仍返回 0(成功),當 name 命名為"ABC="時則會出錯。

測試代碼

#include<stdio.h>
#include<stdlib.h>
#include<string.h>int main(void)
{char *val;const char *name="ABD";//從當前的環境變量表中獲得名字為name的環境變量值,保存到val里val=getenv(name);printf("1, %s = %s\n",name,val);//獲取不出來,出一個空值//覆蓋原有的環境變量setenv(name,"haha-day-and-night",1);//再獲取環境變量val=getenv(name);                                                           printf("2, %s = %s\n",name,val);//刪除剛添加的ABDint ret=unsetenv("ABD");//name=value:valueprintf("ret= %d\n",ret); val=getenv(name);printf("3, %s = %s\n",name,val);return 0;
}

在這里插入圖片描述

#include<stdio.h>
#include<stdlib.h>
#include<string.h>int main(void)
{char *val;const char *name="ABD";//從當前的環境變量表中獲得名字為name的環境變量值,保存到val里val=getenv(name);printf("1, %s = %s\n",name,val);//獲取不出來,出一個空值//覆蓋原有的環境變量setenv(name,"haha-day-and-night",1);//再獲取環境變量val=getenv(name);printf("2, %s = %s\n",name,val);#if 1int ret=unsetenv("ABDFGH");//name=value:valueprintf("ret= %d\n",ret);val=getenv(name);printf("3, %s = %s\n",name,val);#else//刪除剛添加的ABDint ret=unsetenv("ABD");//name=value:valueprintf("ret= %d\n",ret); val=getenv(name);printf("3, %s = %s\n",name,val);
#endif                                                                                                                                                                                                           return 0;
}

在這里插入圖片描述

進程控制

fork 函數

創建一個子進程。一個進程–>2個進程—>各自對fork做返回
pid_tfork(void); 失敗返回-1;成功返回:
① 父進程返回子進程的 ID(非負整數>0,父進程)
②子進程返回 0 pid_t 類型表示進程 ID,但為了表示-1,它是有符號整型。(0 不是有效進程 ID,init 最小,為 1),返回值=0,是子進程
注意返回值,不是 fork 函數能返回兩個值,而是 fork 后,fork 函數變為兩個,父子需【各自】返回一個

getpid 函數

獲取當前進程 ID
pid_tgetpid(void);

getppid 函數

獲取當前進程的父進程 ID
pid_tgetppid(void);
區分一個函數是“系統函數”還是“庫函數”依據:

  1. 是否訪問內核數據結構
  2. 是否訪問外部硬件資源 二者有任一 → 系統函數;二者均無 → 庫函數

getuid 函數

獲取當前進程實際用戶 ID
uid_tgetuid(void);
獲取當前進程有效用戶 ID
uid_tgeteuid(void);

getgid 函數

獲取當前進程使用用戶組 ID
gid_tgetgid(void);
獲取當前進程有效用戶組 ID
gid_tgetegid(void);

創建子進程

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>int main()
{pid_t pid;printf("xxxxxxxxxxxxxx\n");pid=fork();if(pid==-1){   perror("fork error");exit(1);}   else if(pid==0){   printf("I am child\n,pid= %u, ppid= %u\n",getpid(),getppid());}   else{   printf("I am parent\n,pid= %u, ppid= %u\n",getpid(),getppid());sleep(1);}   //這段代碼父子進程都有,所以要打印兩次printf("yyyyyyyyyyyyyyyyyyy\n");                                            }

在這里插入圖片描述
在這里插入圖片描述

循環創建 n 個子進程

一次 fork 函數調用可以創建一個子進程。那么創建 N 個子進程應該是for(i=0;i<n;i++){fork()} 。但這樣創建的并非是N個子進程
在這里插入圖片描述
當 n 為 3 時候,循環創建了(2^n)-1 個子進程,而不是 N 的子進程。需要在循 環的過程,保證子進程不再執行 fork ,因此當(fork()==0)時,子進程應該立即 break;才正確。

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>                                                                    
int main()
{int i;//循環因子pid_t pid;printf("xxxxxxxxxxxxxx\n");for(i=0;i<5;i++){pid=fork();if(pid==-1){perror("fork error");exit(1);}else if(pid==0){break;// printf("I am %d child\n,pid= %u, ppid= %u\n",i+1 ,getpid(),getppid());}else{// printf("I am parent\n,pid= %u, ppid= %u\n",getpid(),getppid());//  sleep(1);}}if(i<5){sleep(i);printf("I am %d child  %u\n",i+1,getpid());}else{sleep(i);printf("I am parent\n");}return 0; 
}

在這里插入圖片描述

進程共享

父子進程之間在 fork 后。有一些相同與不同的地方

父子相同處

剛 fork 之后: 父子相同處:

  1. 全局變量、.
  2. data、
  3. text、
  4. 棧、
  5. 堆、
  6. 環境變量、
  7. 用戶 ID、
  8. 宿主目錄、
  9. 進程工作目錄、
  10. 信號處理方式…

父子不同處:

  1. 進程 ID
  2. fork 返回值
  3. 父進程 ID
  4. 進程運行時間
  5. 鬧鐘(定時器)
  6. 未決信號集
    似乎,子進程復制了父進程 0-3G 用戶空間內容,以及父進程的 PCB,但 pid 不同。真的每 fork 一個子進程都要 將父進程的 0-3G 地址空間完全拷貝一份,然后在映射至物理內存嗎?
    當然不是!父子進程間遵循讀時共享寫時復制(共享一塊物理地址空間)的原則。這樣設計,無論子進程執行父進程的邏輯還是執行自己 的邏輯都能節省內存開銷。

注意

全局變量各自是獨立的不能共享

重點:

父子進程共享:

  1. 文件描述符(打開文件的結構體)
  2. mmap 建立的映射區 (進程間通信詳解)
    特別的,fork 之后父進程先執行還是子進程先執行不確定。取決于內核所使用的調度算法。(隨機爭奪)

gdb 調試

使用 gdb 調試的時候,gdb 只能跟蹤一個進程。可以在 fork 函數調用之前,通過指令設置 gdb 調試工具跟蹤父 進程或者是跟蹤子進程。默認跟蹤父進程。
set follow-fork-mode child 命令設置 gdb 在 fork 之后跟蹤子進程。
set follow-fork-mode parent 設置跟蹤父進程。
注意,一定要在 fork 函數調用之前設置才有效。

list  展示代碼
l    顯示剩余代碼
gcc 文件名  -g
gdb a.out
start/run按什么方式往下走(run自動,start逐步)
next/n往下走
quit退出
b 行數  if  條件  //設置條件斷點
info b  //查看斷點

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383250.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383250.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383250.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

STL-vector

STL學習之二 序列容器&#xff08;vector&#xff09;一、C標準模板庫提供了三種序列容器&#xff1a;vector、list、deque。類模板vector和deque都以數組為基礎&#xff0c;類模板list實現了鏈表的數據結構。STL中最流行的是類模板vector&#xff0c;它是一種更健壯的數據類型…

套接字編程--1(UDP協議編程,端口號,傳輸層協議,網絡字節序)

傳輸層的協議&#xff1a; ip地址&#xff1a; 在網絡中唯一標識一臺主機 IPV4&#xff1a;uint32_t DHCP NATIPV6 : uint8_t addr[16] —向前并不兼容IPV4 每一條數據都必須包含源地址和目的地址&#xff1a;因為每條網絡中的數據都必須確定是從那個主機來到那個主機去 端…

ARP簡單介紹

ARP簡介 ARP&#xff08;Address Resolution Protocol&#xff09;用于將IP地址解析為MAC地址 1. ARP地址解析的必要性 IP地址不能直接用來進行通信&#xff0c;因為網絡設備只能識別MAC地址。IP地址只是主機在網絡層中的地址&#xff0c;如果要將網絡層中傳送的數據報交給…

Linux系統編程--3(exec 函數族,僵尸進程和孤兒進程,wait和wait_pid回收子進程)

exec 函數族 fork 創建子進程后執行的是和父進程相同的程序&#xff08;但有可能執行不同的代碼分支&#xff09; &#xff0c;子進程往往要調用一種 exec 函數以執行另一個程序。當進程調用一種 exec 函數時&#xff0c;該進程的用戶空間代碼和數據完全被新程序替換&#xff…

交換機MAC地址學習和轉發數據幀的原理

1 &#xff1a;交換機 MAC 地址學習在交換機初始化的&#xff0c;也就是剛啟動的時候&#xff0c;交換機的MAC地址表是沒有任何MAC地址和端口的映射條目的 當PCA要想和PCC&#xff0c;PCB,PCD進行通信時&#xff0c;當該二層數據幀通過端口E1/0/1發送到交換機上時&#xff0c…

Linux系統編程---4(進程間通信IPC,管道)

進程間通信目的 數據傳輸&#xff1a;一個進程需要將它的數據發送給另一個進程資源共享&#xff1a;多個進程之間共享同樣的資源。通知事件&#xff1a;一個進程需要向另一個或一組進程發送消息&#xff0c;通知它&#xff08;它們&#xff09;發生了某種事件&#xff08;如進…

沖突域 廣播域簡單解釋

網絡互連設備可以將網絡劃分為不同的沖突域、廣播域。但是&#xff0c;由于不同的網絡互連設備可能工作在OSI模型的不同層次上。因此&#xff0c;它們劃分沖突域、廣播域的效果也就各不相同。如中繼器工作在物理層&#xff0c;網橋和交換機工作在數據鏈路層&#xff0c;路由器工…

Linux系統編程---5(共享存儲映射,存儲映射I/O,mmap函數,父子進程間通信,匿名映射)

共享存儲映射 文件進程間通信 使用文件也可以完成 IPC&#xff0c;理論依據是&#xff0c;fork 后&#xff0c;父子進程共享文件描述符。也就共享打開的文件。 編程&#xff1a;父子進程共享打開的文件。借助文件進行進程間通信。 測試代碼 /*** 父子進程共享打開的文件描述…

變量的存取

一、預備知識―程序的內存分配 一個由c/C編譯的程序占用的內存分為以下幾個部分 1、棧區&#xff08;stack&#xff09;― 由編譯器自動分配釋放 &#xff0c;存放函數的參數值&#xff0c;局部變量的值等。其操作方式類似于數據結構中的棧。 2、堆區&#xff08;heap&#xff…

Linux下文件的多進程拷貝

大文件拷貝 假設有一個超大文件&#xff0c;需對其完成拷貝工作。為提高效率&#xff0c;可采用多進程并行拷貝的方法來實現。假設文件 大小為 len&#xff0c;共有 n 個進程對該文件進行拷貝。那每個進程拷貝的字節數應為 len/n。但未必一定能整除&#xff0c;我們可 以選擇讓…

linux下cron定時任務的總結

cron是linux系統下一個自動執行指定任務的程序&#xff0c;即包含“時間”、“路徑”、“自動執行腳本”等要素 當我們要增加全局性的計劃任務時&#xff0c;一種方式是直接修改/etc/crontab。但是&#xff0c;一般不建議這樣做&#xff0c;/etc/cron.d目錄就是為了解決這種問…

Linux系統編程---6(信號的機制,信號4要素,Linu常規信號表,定時器)

信號的概念 信號在我們的生活中隨處可見&#xff0c; 如&#xff1a;古代戰爭中摔杯為號&#xff1b;現代戰爭中的信號彈&#xff1b;體育比賽中使用的信號槍… 他們都有共性&#xff1a; 簡單不能攜帶大量信息&#xff0c;只能帶一個標志。滿足某個特設條件才發送。 Unix 早…

python httplib2的安裝

window下python安裝httplib2 https://pypi.python.org/pypi/httplib2地址下下載httplib2安裝包&#xff0c;并解壓縮 方法一、我的電腦->屬性->高級->環境變量->系統變量 在系統變量里找到PATH&#xff0c;雙擊PATH&#xff0c;在結尾加上 ";C:\Python25&…

Linux系統編程----7(信號集,信號屏蔽,信號捕捉)

信號集操作函數 內核通過讀取未決信號集來判斷信號是否應被處理。信號屏蔽字 mask 可以影響未決信號集。而我們可以在應 用程序中自定義 set 來改變 mask。已達到屏蔽指定信號的目的。 信號集設定 sigset_t set; //typedef unsigned long sigset_t;int sigemptyset(sigset_t…

Linux系統編程----8(競態條件,時序競態,pause函數,如何解決時序競態)

競態條件(時序競態)&#xff1a; pause 函數 調用該函數可以造成進程主動掛起&#xff0c;等待信號喚醒。調用該系統調用的進程將處于阻塞狀態(主動放棄 cpu) 直 到有信號遞達將其喚醒&#xff0c;等不到一直等 int pause(void); 返回值&#xff1a;-1 并設置 errno 為 EINTR…

Linux系統編程---8(全局變量異步I/O,可重入函數)

全局變量異步 I/O 分析如下父子進程交替 數數 程序。當捕捉函數里面的 sleep 取消&#xff0c;程序即會出現問題。請分析原因。 #include<stdio.h> #include<signal.h> #include<unistd.h> #include<stdlib.h>intn0,flag0; void sys_err(char* s…

http使用post上傳文件時,請求頭和主體信息總結

請求頭必須配置如下行&#xff1a; Content-Type : multipart/form-data; boundary---12321 boundary---12321位文件的分界線 body如下&#xff1a; "-----12321\r\n" //分割文件時加-- "Content-Disposition: form-data; name\"…

iconv 文件編碼轉換

iconv 文件編碼轉換 http://qq164587043.blog.51cto.com/261469/63349 linux shell 配置文件中默認的字符集編碼為UTF&#xff0d;8 。UTF&#xff0d;8是unicode的一種表達方式&#xff0c;gb2312是和unicode都是字符的編碼方式&#xff0c;所以說gb2312跟utf&#xff0d;8的…

Linu系統編程---9(SIGCHLD 信號,信號傳參,中斷系統調用)

SIGCHLD 信號 SIGCHLD 的產生條件 子進程終止時子進程接收到 SIGSTOP 信號停止時子進程處在停止態&#xff0c;接受到 SIGCONT 后喚醒時 借助 SIGCHLD 信號回收子進程 子進程結束運行&#xff0c;其父進程會收到 SIGCHLD 信號。該信號的默認處理動作是忽略。可以捕捉該信號…

Linu系統編程---10(Linux的終端,線路規程,網絡終端,進程組)

終端 輸入輸出設備的總稱 在 UNIX 系統中&#xff0c;用戶通過終端登錄系統后得到一個 Shell 進程&#xff0c;這個終端成為 Shell 進程的控制終端&#xff08;Controlling Terminal&#xff09;&#xff0c; 進程中&#xff0c;控制終端是保存在 PCB 中的信息&#xff0c;而 …