亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Unix > 正文

UNIX高級環境編程(10)進程控制(Process Control)- 競態條件,exec函數,解釋器文件和system函數

2024-06-28 13:21:27
字體:
來源:轉載
供稿:網友
UNIX高級環境編程(10)進程控制(PRocess Control)- 競態條件,exec函數,解釋器文件和system函數

本篇主要介紹一下幾個內容:

  • 競態條件(race condition)
  • exec系函數
  • 解釋器文件?

?

1 競態條件(Race Condition)

競態條件:當多個進程共同操作一個數據,并且結果依賴于各個進程的操作順序時,就會發生競態條件。

例如fork函數執行后,如果結果依賴于父子進程的執行順序,則會發生競態條件。

說到fork之后的父子進程的執行順序,我們可以通過下面的方式指定執行順序:

如果父進程等待子進程結束,則需要調用wait函數。

如果子進程等待父進程結束,則需要像下面這樣輪詢:

while (getppid() != 1)

? ? sleep(1);

輪詢的方式的缺點是非常浪費CPU時間。

?

如果希望避免競態條件和輪詢,則需要用到進程之間的信號機制,或者其他的ipC方式。

競態條件的例子:

Example:

#include "apue.h"

?

static void charatatime(char *);

?

int

main(void)

{

? ? pid_t ? pid;

?

? ? if ((pid = fork()) < 0) {

? ? ? ? err_sys("fork error");

? ? } else if (pid == 0) {

? ? ? ? charatatime("output from child/n");

? ? } else {

? ? ? ? charatatime("output from parent/n");

? ? }

? ? exit(0);

}

?

staticvoid

charatatime(char *str)

{

? ? char? ? *ptr;

? ??int ? ? c;

?

? ? setbuf(stdout, NULL); ? ? ? ? ? /* set unbuffered */

? ? for (ptr = str; (c = *ptr++) != 0; )

? ? ? ? putc(c, stdout);

}

輸出結果:

NewImage

我們可以發現,輸出結果并不一定,依賴于父子進程的執行順序,這里就發生了競態條件。

在例子中,我們設置了stdout得buffer為NULL,為了讓每一個字符的輸出都調用write,這樣可以盡可能多地發生進程間切換。

在下面的例子中,我們通過在父子進程間進行通信,來保證父進程先運行。

Example:

#include "apue.h"

?

static void charatatime(char *);

?

int

main(void)

{

? ? pid_t ? pid;

?

? ? TELL_WAIT();

?

? ? if ((pid = fork()) < 0) {

? ? ? ? err_sys("fork error");

? ? } else if (pid == 0) {

? ? ? ? WAIT_PARENT();? ? ? /* parent goes first */

? ? ? ? charatatime("output from child/n");

? ? } else {

? ? ? ? charatatime("output from parent/n");

? ? ? ? TELL_CHILD(pid);

? ? }

? ? exit(0);

}

static void

charatatime(char *str)

{

? ? char? ? *ptr;

? ? int ? ? c;

?

? ? setbuf(stdout, NULL); ? ? ? ? ? /* set unbuffered */

? ? for (ptr = str; (c = *ptr++) != 0; )

? ? ? ? putc(c, stdout);

}

執行結果:

NewImage

從結果可以看到,輸出是符合預期的。

所以進程間通信是解決競態條件的方式之一。

?

2 exec函數

fork函數的一個作用就是,創建出一個子進程,讓子進程執行exec函數,去執行另一個程序。

exec函數的作用就是用一個新的程序代替現在的進程,從新程序的main函數開始執行。

替換后,進程號不改變,被替換的內容包括文本段,數據段,堆和棧。

exec函數是一組函數,函數聲明如下:

NewImage

函數細節:

  • 前四個函數的參數pathname為文件路徑,后兩個函數的參數filename為文件名,最后一個為文件描述符。如果filename中又’/‘號,則認為是一個文件路徑,否則函數以環境變量為前綴對指定的文件進行搜索;
  • 如果execlp和execvp函數發現目標文件不是可執行文件,則會嘗試把它當做一個腳本調用/bin/sh去執行;
  • fexecve函數依賴調用者去保證文件的可執行,并且防止惡意用戶在時間差將目標可執行文件替換。
  • 函數名中的l代表list,v代表vector。l系函數的參數為命令行中傳入的參數(在參數列表中分別由arg0,arg1,arg2...表示),v系函數則需要將參數的指針放入一個數組中,將數組的地址傳入函數。
  • 環境變量列表的傳遞方式。函數名以e結尾的函數允許修改環境變量列表,函數的最后一個參數是一個指向一個指針數組的指針,數組中的指針指向環境變量的各個字符串。

?這7個函數非常難記,了解函數名中得特別字母有助于記憶:

  • 字母p代表函數獲取一個filenam參數和環境變量來查找可執行文件;
  • 字母l代表函數獲取一個參數列表
  • 字母v代表函數獲取一個argv[]作為參數
  • 字母e代表函數獲取一個envp[]作為參數,取代環境變量列表,用戶可以修改環境變量然后傳遞給子進程

?exec函數小結:

NewImage

前面提到過,執行了exec函數后,進程的進程號不變。除了進程號,還有繼承而來的信息包括:

NewImage

exec函數替換程序之后,對于已經打開的文件描述符的處理,取決于flag close-on-exec。如果flag close-on-exec被打開,則exec替換程序后,打開的文件描述符會被關閉,負責這些文件描述會保持打開狀態,這種保持打開狀態的行為也是默認行為。

?real user ID和real group ID在exec函數后保持不變,但是effective user ID和effective group ID可以通過設置set-user-ID和set-group-ID標志位而決定是否改變。

一般實現時,7個exec函數,只有一個exec函數會被實現為系統調用。

7個exec函數之間的關系如圖所示:

NewImage

?

Example:

#include "apue.h"

#include <sys/wait.h>

?

char? ? *env_init[] = { "USER=unknown", "PATH=/tmp", NULL };

?

int

main(void)

{

? ? pid_t ? pid;

?

? ? if ((pid = fork()) < 0) {

? ? ? ? err_sys("fork error");

? ? } elseif (pid == 0) {? /* specify pathname, specify environment */

? ? ? ? if (execle(“/*可執行文件所在路徑*//echoall", "echoall", "myarg1",

? ? ? ? ? ? ? ? "MY ARG2", (char *)0, env_init) < 0)

? ? ? ? ? ? err_sys("execle error");

? ? }

?

? ? if (waitpid(pid, NULL, 0) < 0)

? ? ? ? err_sys("wait error");

?

? ? if ((pid = fork()) < 0) {

? ? ? ??err_sys("fork error");

? ? } elseif (pid == 0) {? /* specify filename, inherit environment */

? ? ? ? if (execlp("echoall", "echoall", "only 1 arg", (char *)0) < 0)

? ? ? ? ? ? err_sys("execlp error");

? ? }

?

? ? exit(0);

}

?

3 解釋器文件(Interpreter Files)

所有現代UNIX系統都支持解釋器文件(interpreter files)。

解釋器文件開始一行的格式為:

#!pathname [optional-argument]

?例如,shell腳本的開始一行為:

?#!/bin/sh?

?要區分清楚解釋器文件和解釋器:

  • 解釋器文件:第一行以#!pathname XXX開始的文本文件
  • 解釋器:解釋器文件第一行#!pathname xxx中指定的xxx可執行文件

?需要注意的一點是:解釋器文件的第一行的長度是有限制的,長度計算包含了空格,’#!’和換行符。

Example:

#include "apue.h"

#include <sys/wait.h>

?

int

main(void)

{

? ? pid_t ? pid;

?

? ? if ((pid = fork()) < 0) {

? ? ? ? err_sys("fork error");

? ? } else if (pid == 0) {? ? ? ? ? /* child */

? ? ? ? if (execl("/home/sar/bin/testinterp",

? ? ? ? ? ? ? ? ? “testinterp", "myarg1", "MY ARG2", (char *)0) < 0)

? ? ? ? ? ? err_sys("execl error");

? ? }

? ? if (waitpid(pid, NULL, 0) < 0)? /* parent */

? ? ? ? err_sys("waitpid error");

? ? exit(0);

}

輸出結果:

NewImage?

?輸出結果說明:

  • 程序的作用是輸出命令行中的每一個參數
  • 需要注意的是,第一個參數argv[0]是解釋器的據對路徑
  • 第二個參數是解釋器文件第一行的可選參數
  • 第三個參數是替換程序文件的路徑
  • 需要注意的是,參數’’testinterp”并沒有被輸出,因為內核認為第一個參數pathname包含更多的內容

?

4 system函數(system Function)

在程序執行一個命令字符串是很方便的。

例如:

system(“date > file");

?將日期重定向至file文件中。

函數聲明:

#include <stdlib.h>

int system(const char* cmdstring);

?函數細節:

  • 如果cmdstring是一個Null指針,則在system函數可以正常調用時返回非零值。這個特性可以用來檢查系統是否支持system函數。
  • 因為system函數是基于fork, exec和waitpid實現,所以system有三種返回值
    • 如果fork失敗或者waitpid返回錯誤并且不是EINTR,system函數返回-1;
    • 如果exec失敗,表明shell不能被執行,返回值和shell退出返回值(127)相同;
    • 如果fork,exec和waitpid都執行成功,并且system返回值是shell的終止狀態值,該值的形式由waitpid函數指定。

?system函數的一種實現,沒有處理信號的版本。

code

#include? ? <sys/wait.h>

#include? ? <errno.h>

#include? ? <unistd.h>

?

int

system(constchar *cmdstring) ? /* version without signal handling */

{

? ? pid_t ? pid;

? ? int ? ? status;

?

? ? if (cmdstring == NULL)

? ? ? ? return(1);? ? ? /* always a command processor with UNIX */

?

? ? if ((pid = fork()) < 0) {

? ? ? ? status = -1;? ? /* probably out of processes */

? ? } else if (pid == 0) {? ? ? ? ? ? ? /* child */

? ? ? ? execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);

? ? ? ? _exit(127); ? ? /* execl error */

? ? } else {? ? ? ? ? ? ? ? ? ? ? ? ? ? /* parent */

? ? ? ? while (waitpid(pid, &status, 0) < 0) {

? ? ? ? ? ? if (errno != EINTR) {

? ? ? ? ? ? ? ? status = -1; /* error other than EINTR from waitpid() */

? ? ? ? ? ? ? ? break;

? ? ? ? ? ??}

? ? ? ? }

? ? }

?

? ? return(status);

}

?代碼細節:

  • shell中的-c參數說明將后面的一個參數作為命令行輸入,而不是從標準輸入或者指定文件讀?。?/li>
  • 我們調用_exit而不是exit,防止子進程退出時,會將從父進程拷貝到的buffer打印。

使用system函數的好處是system函數為我們處理了所以的異常,并且提供了所有必須的信號處理。

Example

#include "apue.h"

#include <sys/wait.h>

?

int

main(void)

{

? ? int ? ? status;

?

? ? if ((status = system("date")) < 0)

? ? ? ? err_sys("system() error");

?

? ? pr_exit(status);

?

? ? if ((status = system("nosuchcommand")) < 0)

? ? ? ? err_sys("system() error");

?

? ? pr_exit(status);

?

? ? if ((status = system("who; exit 44")) < 0)

? ? ? ? err_sys("system() error");

?

? ? pr_exit(status);

?

? ? exit(0);

}

運行結果:

NewImage

?

?

參考資料:

《Advanced Programming in the UNIX Envinronment 3rd》


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品99久久久久中文字幕| 亚洲伊人一本大道中文字幕| 欧美成人免费va影院高清| 毛片精品免费在线观看| 国产精品99蜜臀久久不卡二区| 欧美日韩国产一中文字不卡| 欧美夜福利tv在线| 国产91精品久久久| 精品中文字幕乱| 亚洲成人久久久久| 91禁国产网站| 久久亚洲私人国产精品va| 日韩电影大全免费观看2023年上| 欧美成人精品xxx| 91黄色8090| 亚洲在线视频观看| 亚洲欧美制服另类日韩| 欧美精品18videos性欧| 欧美剧在线观看| 午夜精品久久久久久久白皮肤| 久久99热这里只有精品国产| 另类专区欧美制服同性| 亚洲欧美日韩一区在线| 欧美极品少妇xxxxⅹ裸体艺术| 日韩欧美高清视频| 久久久久亚洲精品国产| 亚洲欧美中文日韩v在线观看| 一区二区三区四区精品| 日韩视频免费中文字幕| 精品亚洲aⅴ在线观看| 国产69精品99久久久久久宅男| 亚洲人成网7777777国产| 欧美资源在线观看| 国产成人91久久精品| 全亚洲最色的网站在线观看| 91在线视频九色| 欧美猛少妇色xxxxx| 一夜七次郎国产精品亚洲| 777国产偷窥盗摄精品视频| 91探花福利精品国产自产在线| 不卡av电影院| 亚洲理论电影网| 日韩欧美成人精品| 久久久久久亚洲精品中文字幕| 亚洲免费人成在线视频观看| 日韩美女写真福利在线观看| 亚洲高清久久久久久| 国模gogo一区二区大胆私拍| 欧美一区二粉嫩精品国产一线天| 久久久精品在线观看| 精品欧美一区二区三区| 色综合色综合久久综合频道88| 日韩在线国产精品| 91在线观看免费高清| 色老头一区二区三区在线观看| 欧美黑人又粗大| 亚洲国产97在线精品一区| 日韩精品免费电影| 国内免费精品永久在线视频| 中日韩美女免费视频网站在线观看| 欧洲s码亚洲m码精品一区| 日韩精品中文字幕在线| 国产精品大陆在线观看| 亚洲国产精品嫩草影院久久| 日韩av色在线| www.亚洲一区| 一本色道久久综合亚洲精品小说| 亚洲国产精品推荐| 亚洲欧美激情精品一区二区| 日韩欧美国产视频| 97视频在线看| 成人疯狂猛交xxx| 91国产高清在线| 国产精品极品尤物在线观看| 精品一区电影国产| 日韩综合中文字幕| 国产精品国产三级国产专播精品人| 久久精品电影一区二区| 国产成人鲁鲁免费视频a| 欧美成人精品在线视频| 欧美激情视频一区| 亚洲大胆人体在线| 国产aⅴ夜夜欢一区二区三区| 亚洲欧美精品中文字幕在线| 成人激情av在线| 国产精品美女免费看| 高清一区二区三区四区五区| 国产精品久久久久久搜索| 日韩在线观看av| 国产精品一区二区3区| 精品国产欧美成人夜夜嗨| 亚洲精品欧美日韩| 国产美女扒开尿口久久久| 日韩av网站电影| 亚洲人午夜精品免费| 一区二区成人精品| 国产精品久久久久久久久久久新郎| 久久久久久91| 国产精品91久久久| 欧美日韩激情美女| 久久69精品久久久久久久电影好| 欧美成年人在线观看| 国产精品日韩在线| 成人免费观看49www在线观看| 一区二区欧美日韩视频| 久久久99久久精品女同性| 亚洲免费av网址| 孩xxxx性bbbb欧美| 九九热r在线视频精品| 亚洲黄色有码视频| 国产欧美亚洲精品| 亚洲欧美日韩天堂一区二区| 日韩高清电影免费观看完整版| 色99之美女主播在线视频| 日韩国产欧美精品在线| 亚洲欧美日韩区| 欧美尤物巨大精品爽| 久久久电影免费观看完整版| 97视频在线观看免费高清完整版在线观看| 九九热这里只有在线精品视| 欧美高清在线播放| 亚洲精品国精品久久99热| 91免费精品视频| 国产美女主播一区| 欧美性xxxxx| 日韩福利伦理影院免费| 日韩精品有码在线观看| 欧美色videos| 欧美日韩国产一区在线| 91高潮精品免费porn| 黑人狂躁日本妞一区二区三区| 亚洲天堂av高清| 日韩欧美中文免费| 国内精品免费午夜毛片| 欧美激情视频给我| 久久91精品国产91久久久| 亚洲成人在线视频播放| 欧美老肥婆性猛交视频| 久久久999精品视频| 亚洲第一视频在线观看| 国产亚洲人成网站在线观看| 欧美日韩日本国产| 国产精品国产亚洲伊人久久| 欧美一级片久久久久久久| 日韩免费观看av| 亚洲欧洲黄色网| 欧美精品videosex极品1| 欧美久久久精品| 日本精品va在线观看| 欧美激情影音先锋| 国产有码在线一区二区视频| 亚洲www永久成人夜色| 日韩av影院在线观看| 久久久久久久久久久久久久久久久久av| 日韩高清电影免费观看完整| 日本一区二区不卡| 久久露脸国产精品| 精品无人区乱码1区2区3区在线| 国产精品一区二区三区成人| 亚洲三级 欧美三级| 亚洲视频网站在线观看| 欧美香蕉大胸在线视频观看| 这里精品视频免费| 国产精品日韩精品|