中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

廈門廣告公司有哪些aso優(yōu)化的主要內(nèi)容為

廈門廣告公司有哪些,aso優(yōu)化的主要內(nèi)容為,淄博住房和城鄉(xiāng)建設(shè)局網(wǎng)站,隨州抖音seo收費(fèi)標(biāo)準(zhǔn)Linux進(jìn)程控制(2) 📟作者主頁(yè):慢熱的陜西人 🌴專欄鏈接:Linux 📣歡迎各位大佬👍點(diǎn)贊🔥關(guān)注🚓收藏,🍉留言 本博客主要內(nèi)容講解了進(jìn)程等待收尾內(nèi)容和進(jìn)程的程序…

Linux進(jìn)程控制(2)

📟作者主頁(yè):慢熱的陜西人

🌴專欄鏈接:Linux

📣歡迎各位大佬👍點(diǎn)贊🔥關(guān)注🚓收藏,🍉留言

本博客主要內(nèi)容講解了進(jìn)程等待收尾內(nèi)容和進(jìn)程的程序替換,以及進(jìn)程程序替換的原理,進(jìn)程程序替換的7個(gè)重要接口

文章目錄

  • Linux進(jìn)程控制(2)
    • 1.進(jìn)程等待(續(xù))
    • 2.進(jìn)程程序替換
      • 2.1 程序替換是如何完成的---單線程版
      • 2.2程序替換的原理
      • 2.3引入多進(jìn)程,使用所有程序替換的接口
        • 熟悉所有的替換程序接口(7個(gè))

1.進(jìn)程等待(續(xù))

我們稍微改造一下,之前進(jìn)程等待的時(shí)候,父進(jìn)程不要阻塞等待的代碼,讓父進(jìn)程真正的去運(yùn)行一些任務(wù)。

我們采用函數(shù)回調(diào)的方式,讓父進(jìn)程在等待子進(jìn)程的時(shí)候也可以去運(yùn)行自己的一些任務(wù)!

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdlib.h>#define TASK_NUM 10//預(yù)設(shè)一批任務(wù)
void sync_disk()
{printf("這是一個(gè)刷新數(shù)據(jù)的任務(wù)\n");
}void sync_log()
{printf("這是一個(gè)同步日志的任務(wù)\n");
}void net_send()
{printf("這是一個(gè)網(wǎng)絡(luò)發(fā)送的任務(wù)\n");
}                                                                                                                                                            //保存相關(guān)的任務(wù)
typedef void (*func_t)(); //定義了一個(gè)函數(shù)指針類型
func_t orther_task[TASK_NUM] = {NULL}; //裝載任務(wù)
int Load_Task(func_t fuc)
{int i = 0;for(; i < TASK_NUM; ++i){if(orther_task[i] == NULL) break;}if(TASK_NUM == i) return -1;else orther_task[i] = fuc;return 0;
}//初始化函數(shù)指針數(shù)組
void Init_Task()
{for(int i = 0; i < TASK_NUM; ++i) orther_task[i] = NULL;Load_Task(sync_disk);  Load_Task(sync_log);Load_Task(net_send);
}void Run_Task()
{for(int i = 0; i < TASK_NUM; ++i){if(orther_task[i] == NULL) continue;else orther_task[i]();}
}int main()
{pid_t id = fork();if(id == 0){//子進(jìn)程int cnt = 5;while(cnt){printf("我是子進(jìn)程,我還活著呢,我還有%dS,我的pid:%d,我的ppid:%d\n", cnt--, getpid(), getppid());sleep(1);}exit(0);}Init_Task();while(1){int status = 0;pid_t ret_id = waitpid(id, &status, WNOHANG);// 夯住了if(ret_id < 0){printf("waitpid_error\n");}else if(ret_id == 0){Run_Task();                                                                                                                                          sleep(1);continue;}else{printf("我是父進(jìn)程,我等待成功了,我的pid:%d,我的ppid:%d, ret_id: %d, child exit code: %d, child exit signal:%d\n",getpid(), getppid(), ret_id, (status >> 8)&0xFF, status & 0x7F);exit(0);}sleep(1); }return 0;
}

運(yùn)行結(jié)果:

image-20231109151934831

繼續(xù)改進(jìn),我們之前獲取進(jìn)程退出碼的時(shí)候是使用(status >> 8)& 0xFF的方式來(lái)進(jìn)行獲取的,那么實(shí)際上C庫(kù)也給我們提供了兩個(gè)宏來(lái)幫助我們獲取進(jìn)程的退出碼:

status:
WIFEXITED(status): 若為正常終止子進(jìn)程返回的狀態(tài),則為真。(查看進(jìn)程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子進(jìn)程退出碼。(查看進(jìn)程的退出碼)

我們用這兩個(gè)宏來(lái)優(yōu)化一下我們等待成功,也就是子進(jìn)程結(jié)束的時(shí)候的代碼:

      else                                                                                       {                                                                                            //等待成功                                                                                   if(WIFEXITED(status))                                                       {                                                                                         //正常退出                                                                                 printf("wait success, child exit code :%d", WEXITSTATUS(status));                           }                                                                                             else {                                                                                             //異常退出                                                                                printf("wait success, child exit signal :%d", status & 0x7F);    }            exit(0);    }   

正常退出:

image-20231109153300831

異常退出:我們嘗試在父進(jìn)程等待的時(shí)候殺掉子進(jìn)程:

image-20231109153505131

2.進(jìn)程程序替換

我們?yōu)槭裁葱枰獎(jiǎng)?chuàng)建子進(jìn)程?為了讓子進(jìn)程幫我執(zhí)行特定的任務(wù);

①讓子進(jìn)程執(zhí)行父進(jìn)程的一部分代碼;

②如果子進(jìn)程指向一段全新的代碼呢?這時(shí)候我們就需要進(jìn)程的程序替換!

也是為什么需要進(jìn)程的程序替換。

2.1 程序替換是如何完成的—單線程版

代碼:

#include<stdio.h>    
#include<stdlib.h>    
#include<unistd.h>    int main()    
{    printf("begin......\n");    printf("begin......\n");    printf("begin......\n");    printf("begin......\n");    printf("begin......\n");    execl("/bin/ls", "ls", "-a", "-l", NULL);                                                           printf("end........\n");    printf("end........\n");    printf("end........\n");    printf("end........\n");    printf("end........\n");    return 0;    
}  

運(yùn)行結(jié)果:

那么我們可以看到這個(gè)進(jìn)程運(yùn)行了開始的begin....,然后運(yùn)行了ls,但是后面的end...卻不見(jiàn)了。

這是因?yàn)榘l(fā)生了進(jìn)程的程序的替換,簡(jiǎn)要的原理就是,操作系統(tǒng)通過(guò)提供的地址/bin/ls從磁盤中拿出ls然后選到指定的文件ls,在輸入一些參數(shù)-a, -l,以NULL表示結(jié)束。

image-20231109162541803

2.2程序替換的原理

操作系統(tǒng)不動(dòng)當(dāng)前進(jìn)程的內(nèi)核數(shù)據(jù)結(jié)構(gòu),而是去磁盤內(nèi)部拿到要替換的數(shù)據(jù)和代碼,將我們當(dāng)前進(jìn)程的數(shù)據(jù)和代碼替換掉。

當(dāng)進(jìn)程調(diào)用一種exec函數(shù)時(shí),該進(jìn)程的用戶空間代碼和數(shù)據(jù)完全被新程序替換,從新程序的啟動(dòng)例程開始執(zhí)行。

所以進(jìn)程的程序替換,是沒(méi)有創(chuàng)建新的進(jìn)程的。

image-20231109163349868

①站在進(jìn)程的角度

操作系統(tǒng),幫我們?cè)诖疟P內(nèi)部找到我們要替換的數(shù)據(jù)和代碼,替換進(jìn)程的數(shù)據(jù)和代碼。

②站在程序的角度

這個(gè)程序被加載了,所以我們也稱execl這類函數(shù)為加載器

我們?cè)诨氐揭婚_始,為什么我們程序后面的end.....卻沒(méi)有打印出來(lái)?

image-20231109164919209

原因是當(dāng)我們加載程序替換的時(shí)候,新的數(shù)據(jù)和代碼就進(jìn)入了進(jìn)程,當(dāng)前進(jìn)程后續(xù)沒(méi)有沒(méi)運(yùn)行的代碼就成為了老代碼,直接被替換了,沒(méi)有機(jī)會(huì)執(zhí)行了。

所以進(jìn)程的程序替換是整體替換,而不是局部替換

所以我們接下來(lái)引入多進(jìn)程的程序替換

2.3引入多進(jìn)程,使用所有程序替換的接口

例程:

#include<stdio.h>    
#include<stdlib.h>    
#include<unistd.h>    
#include<sys/types.h>    
#include<sys/wait.h>    int main()    
{    pid_t id = fork();    if(id == 0)    {    //child    printf("我是子進(jìn)程:%d", getpid());    execl("/bin/ls", "ls", "-a", "-l", NULL);    }    sleep(2);    //father    waitpid(id, NULL, 0);    printf("我是父進(jìn)程:%d\n", getpid());                                                                                                                      return 0;    
}

運(yùn)行結(jié)果:

我們看到execl之后父進(jìn)程的內(nèi)容也被運(yùn)行了

因?yàn)檫M(jìn)程的獨(dú)立性,所以進(jìn)程的程序替換只會(huì)影響調(diào)用程序替換的子進(jìn)程。

子進(jìn)程加載新程序的時(shí)候,是需要進(jìn)行程序替換的,發(fā)生寫時(shí)拷貝(子進(jìn)程執(zhí)行的可是全新的代碼啊,新的代碼,所以代碼區(qū)也可以發(fā)生寫時(shí)拷貝)

image-20231109172035019

那么對(duì)于execl這類加載函數(shù),它有沒(méi)有返回值呢?

答案是分情況:

①替換成功是沒(méi)有返回值的

②替換失敗是有返回值的-1

原因是:假設(shè)替換替換成功了,那么我們?cè)撨M(jìn)程中的代碼和數(shù)據(jù),都會(huì)被替換成新的代碼和數(shù)據(jù),那么我們之前的返回值也就不復(fù)存在了,并且我們也不需要返回值了。

替換失敗的情況下,進(jìn)程之前的代碼和數(shù)據(jù)還是存在的,那么我們的返回值也是存在的,從而可以返回。

所以我們調(diào)用了加載函數(shù)之后我們不用去判斷它是否加載成功,只需要在函數(shù)后面返回異常即可。

失敗的例程:

#include<stdio.h>    
#include<stdlib.h>    
#include<unistd.h>    
#include<sys/types.h>    
#include<sys/wait.h>    int main()    
{    pid_t id = fork();    if(id == 0)    {    //child    printf("我是子進(jìn)程:%d\n", getpid());                                                                                                                    execl("/bin/lsss", "lsss", "-a", "-l", NULL);    exit(1);    }    sleep(2);    //father    int status;    waitpid(id,&status, 0);    printf("我是父進(jìn)程:%d, child exit signal:%d\n", getpid(), WEXITSTATUS(status));    return 0;    
} 

image-20231109173257987

熟悉所有的替換程序接口(7個(gè))

int execl(const char *path, const char *arg, ...);

例如:execl("/bin/ls", "ls", "-a", "-l", NULL);

l代表list;

path:路徑,也就是告訴操作系統(tǒng),你要用來(lái)替換的程序,在磁盤的哪個(gè)路徑,例程里的/bin/ls

arg:文件,是你要用來(lái)替換的文件名,例程里面的ls。

其中的...是可變參數(shù)列表,例程中的那些參數(shù)-a , -l

其中最后我們要特別的輸入一個(gè)NULL參數(shù),告訴函數(shù)參數(shù)結(jié)束了;

int execv(const char *path, char *const argv[]);

相比較第一個(gè)函數(shù)的差別就是,第一個(gè)函數(shù)要求我們一個(gè)一個(gè)的去傳參數(shù),而第二個(gè)要求我們直接用數(shù)組的形式去傳,但是原則也是一樣的,數(shù)組的最后一個(gè)元素也要置成NULL。

我們?cè)谧舆M(jìn)程內(nèi)部調(diào)用的時(shí)候是這樣的:

先創(chuàng)建一個(gè)數(shù)組,將這些參數(shù)一個(gè)一個(gè)放進(jìn)去,再傳給execv即可

那么其實(shí)v就是vector就是數(shù)組的意思;

   char* const argv[] =    {    "ls",    "-a",    "-l",    NULL    };    // execl("/bin/lsss", "lsss", "-a", "-l", NULL);    execv("/bin/ls", argv);                                                                                                                                 exit(1);    }    

運(yùn)行結(jié)果:

image-20231109175259752

int execlp(const char *file, const char *arg, ...);

p:當(dāng)我們指定執(zhí)行程序的時(shí)候,只需要指定程序名即可,系統(tǒng)會(huì)自動(dòng)在**環(huán)境變量PATH**中查找。

也就是說(shuō)我們要用于替換的程序,必須在環(huán)境變量PATH中,或者說(shuō)我們?cè)诃h(huán)境變量PATH中設(shè)置過(guò);

 execlp("ls", "ls", "-a", "-l", NULL);    

image-20231109180335737

那么其中的兩個(gè)ls是不一樣的,一個(gè)是文件名,一個(gè)是參數(shù)。

int execvp(const char *file, char *const argv[]);

v:表示參數(shù)以數(shù)組的形式傳入;

p:表示在環(huán)境變量PATH中去尋找用于替換的文件;

   char* const argv[] =                                                                                                                                   {    "ls",    "-a",    "-l",    NULL    };    execvp("ls", argv);    

運(yùn)行結(jié)果:

image-20231109181025149

int execle(const char *path, const char *arg, ..., char * const envp[]);

envp[]:叫做自定義環(huán)境變量,當(dāng)我們不想使用系統(tǒng)默認(rèn)的環(huán)境變量的時(shí)候,這個(gè)時(shí)候我們就傳遞一個(gè)envp

比如我們現(xiàn)在要讓我們的調(diào)用exec目錄下的ortherproc來(lái)替換myproc的子進(jìn)程的后續(xù)代碼

image-20231109182618129

先用execl嘗試一下:

 execl("./exec/ortherproc", "ortherproc", NULL);  

運(yùn)行結(jié)果:

image-20231109182932018

換成的動(dòng)態(tài)的效果再看看:

動(dòng)態(tài)效果

下來(lái)我們嘗試用execle來(lái)實(shí)現(xiàn)一下:

proc.c

   char* const envp[] =                                                                                                             {                                                                                                                                "MYENVP=UCanCMe!",    NULL    };    execle("./exec/ortherproc", "ortherproc",envp);  

ortherproc.cc

for(int i = 0; i < 5; ++i)      
{      cout << "我是另一個(gè)程序,我的PID是 :" << getpid() << endl;      cout << "MYENVP: " << (getenv("MYENVP")==NULL ? "NULL" : getenv("MYENVP")) << endl;           cout << "PATH: " << (getenv("PATH") == NULL ? "NULL" : getenv("PATH")) << endl;      sleep(1);                                                                     
}     

運(yùn)行結(jié)果:

我們看到自定環(huán)境變量打印出來(lái)了,但是操作系統(tǒng)內(nèi)部的環(huán)境變量卻不見(jiàn)了,所以我們可以得到一個(gè)結(jié)論:

自定義環(huán)境變量覆蓋了,默認(rèn)的環(huán)境變量;

image-20231109193230574

我們傳默認(rèn)的環(huán)境變量試試:

extern char ** environ;execle("./exec/ortherproc", "ortherproc",NULL , environ);  

運(yùn)行結(jié)果:

image-20231109193621091

那么如果我們兩個(gè)都要呢,那么有一個(gè)接口putenv給我們提供了一個(gè)將自定義環(huán)境變量追加到進(jìn)程的默認(rèn)環(huán)境變量的方法:接下來(lái)我們嘗試一下

   putenv("MYENVP=UCanCMe");    execle("./exec/ortherproc", "ortherproc", NULL, environ);  

運(yùn)行結(jié)果:

image-20231109201734620

插播一段

我們知道環(huán)境變量具有全局屬性,可以被子進(jìn)程繼承下去,那么操作系統(tǒng)是怎么辦到的?

只需要用execle的最后一個(gè)參數(shù)傳過(guò)去即可!

那么我們是不是不需要putenv也能實(shí)現(xiàn)兩個(gè)都能被子進(jìn)程讀取到呢?

我們直接把自定義的環(huán)境變量exportbash中試試:

[mi@lavm-5wklnbmaja lesson6]$ export MYENVP=UCanCMe
[mi@lavm-5wklnbmaja lesson6]$ echo $MYENVP
UCanCMe

運(yùn)行結(jié)果:

我們發(fā)現(xiàn)是可行的,自定義環(huán)境變量-----> bash ----->父進(jìn)程------>子進(jìn)程

image-20231109202438896

int execvpe(const char *file, char *const argv[], char *const envp[]);

p:不需要指定路徑,只要在環(huán)境變量?jī)?nèi)部即可;

v:參數(shù)以數(shù)組的形式傳入;

e:環(huán)境變量數(shù)組傳入;

使用方法都與上面的類似。

int execve(const char *filename, char *const argv[], char *const envp[]);

這個(gè)接口也不用過(guò)多介紹了,使用方法都是一樣的。

那么我們需要注意的是,在linux的man手冊(cè)中將區(qū)域六個(gè)接口都放在了3號(hào)手冊(cè),唯獨(dú)這個(gè)卻放在了2號(hào)手冊(cè)。

其實(shí)操作系統(tǒng)只給我們提供了一個(gè)程序替換的接口execve,剩下的幾個(gè)接口都是由這個(gè)接口封裝出來(lái)的。

image-20231109204020146

并且我們程序替換的時(shí)候不僅可以替換C語(yǔ)言的,甚至其他的語(yǔ)言都可以替換,我上面的例子也做到了用C++替換,因?yàn)檫@些代碼都是交給操作系統(tǒng)來(lái)處理的而不是編譯器,所以不論是什么語(yǔ)言都是可以替換的!

到這本篇博客的內(nèi)容就到此結(jié)束了。
如果覺(jué)得本篇博客內(nèi)容對(duì)你有所幫助的話,可以點(diǎn)贊,收藏,順便關(guān)注一下!
如果文章內(nèi)容有錯(cuò)誤,歡迎在評(píng)論區(qū)指正

在這里插入圖片描述

http://www.risenshineclean.com/news/29156.html

相關(guān)文章:

  • wordpress修改谷歌外貿(mào)seo公司
  • 做美團(tuán)網(wǎng)這種網(wǎng)站賺錢嗎亞馬遜關(guān)鍵詞搜索器
  • 英語(yǔ)網(wǎng)站建設(shè)如何制作一個(gè)公司網(wǎng)站
  • 上海網(wǎng)站建設(shè)平臺(tái)站霸網(wǎng)絡(luò)seo學(xué)習(xí)網(wǎng)站
  • 做網(wǎng)站有一個(gè)火箭回頂部網(wǎng)站優(yōu)化關(guān)鍵詞公司
  • 做cpa的博客網(wǎng)站類型博客網(wǎng)
  • 優(yōu)惠券推廣網(wǎng)站怎么做seo怎么搞
  • nas網(wǎng)站怎么做網(wǎng)站時(shí)事新聞最新2022
  • 順德樂(lè)從有做阿里巴巴的網(wǎng)站嗎sem競(jìng)價(jià)專員是干什么的
  • 做網(wǎng)站視頻圖片加載不出來(lái)企業(yè)網(wǎng)站模板下載
  • 情感視頻素材網(wǎng)站劉連康seo培訓(xùn)哪家強(qiáng)
  • 網(wǎng)站建設(shè)和網(wǎng)站推廣可以同一家做嗎網(wǎng)站優(yōu)化排名金蘋果系統(tǒng)
  • 企業(yè)網(wǎng)站建設(shè)英文超級(jí)外鏈
  • 手機(jī)網(wǎng)站哪家好西安百度推廣優(yōu)化
  • 網(wǎng)站開發(fā) 英文文章百度收錄快的發(fā)帖平臺(tái)
  • 福州網(wǎng)頁(yè)鄭州seo排名優(yōu)化公司
  • 汕頭網(wǎng)站建設(shè)制作公司衡陽(yáng)seo快速排名
  • 分類信息網(wǎng)站成都搭建如何搭建一個(gè)網(wǎng)站平臺(tái)
  • 做網(wǎng)站的點(diǎn)子站長(zhǎng)之家ppt素材
  • 同程網(wǎng)站建設(shè)分析朝陽(yáng)網(wǎng)站建設(shè)公司
  • 深圳住建委網(wǎng)站智謀網(wǎng)站優(yōu)化公司
  • html5門戶網(wǎng)站模板百度人工客服電話多少
  • 鄭州做網(wǎng)站九零后排名點(diǎn)擊工具
  • 網(wǎng)站開發(fā)程序員 工資百度云怎么找資源
  • 貴陽(yáng)網(wǎng)站建設(shè)多少錢?影視后期培訓(xùn)機(jī)構(gòu)全國(guó)排名
  • 如何搭建公司網(wǎng)站上海公關(guān)公司
  • 做美圖 網(wǎng)站有哪些付費(fèi)惡意點(diǎn)擊軟件
  • 做局域網(wǎng)網(wǎng)站教程?hào)|莞網(wǎng)絡(luò)優(yōu)化調(diào)查公司
  • 慈溪企業(yè)排名網(wǎng)站培訓(xùn)機(jī)構(gòu)排名全國(guó)十大教育機(jī)構(gòu)排名
  • 做腳本網(wǎng)站建站公司最新報(bào)價(jià)