1. 程式人生 > >系統呼叫system失敗的原因分析

系統呼叫system失敗的原因分析

fork()與vfock()都是建立一個程序,那他們有什麼區別呢?總結有以下三點區別: 
1.  fork  ():子程序拷貝父程序的資料段,程式碼段 
    vfork ( ):子程序與父程序共享資料段 
2.  fork ()父子程序的執行次序不確定 
    vfork 保證子程序先執行,在呼叫exec 或exit 之前與父程序資料是共享的,在它呼叫exec
     或exit 之後父程序才可能被排程執行。 
3.  vfork ()保證子程序先執行,在她呼叫exec 或exit 之後父程序才可能被排程執行。如果在
   呼叫這兩個函式之前子程序依賴於父程序的進一步動作,則會導致死鎖。 

下面通過幾個例子加以說明: 
第一:子程序拷貝父程序的程式碼段的例子: 

  1. #include<sys/types.h>
  2. #include<unistd.h>
  3. #include<stdio.h>
  4. int main()  
  5. {  
  6.     pid_t pid;  
  7.     pid = fork();  
  8.     if(pid<0)  
  9.         printf("error in fork!\n");  
  10.     elseif(pid == 0)  
  11.         printf("I am the child process,ID is %d\n",getpid());  
  12.     else
  13.         printf("I am the parent process,ID is %d\n",getpid());  
  14.     return 0;  
  15. }  


執行結果: 

  1. [[email protected] fork]# gcc -o fork fork.c   
  2. [[email protected] fork]# ./fork  
  1. I am the child process,ID is 4711  
  2. I am the parent process,ID is 4710  


為什麼兩條語 都會列印呢?這是因為fork()函式用於從已存在的程序中建立一個新的進 
程,新的程序稱為子程序,而原程序稱為父程序,fork ()的返回值有兩個,子程序返回0,


父程序返回子程序的程序號,程序號都是非零的正整數,所以父程序返回的值一定大於零,
在pid=fork();語句之前只有父程序在執行,而在pid=fork();之後,父程序和新建立的子程序 
都在執行,所以如果pid==0,那麼肯定是子程序,若pid !=0 (事實上肯定大於0),那麼是 
父程序在執行。而我們知道fork()函式子程序是拷貝父程序的程式碼段的,所以子程序中同樣 
有 
if(pid<0) 
         printf("error in fork!"); 
     else if(pid==0) 
         printf("I am the child process,ID is %d\n",getpid()); 
     else 
         printf("I am the parent process,ID is %d\n",getpid()); 

這麼一段程式碼,所以上面這段程式碼會被父程序和子程序各執行一次,最終由於子程序的pid= =0,

而打印出第一句話,父程序的pid>0,而打印出第二句話。於是得到了上面的執行結果。 
再來看一個拷貝資料段的例子: 

  1. #include<sys/types.h>
  2. #include<unistd.h>
  3. #include<stdio.h>
  4. int main()  
  5. {  
  6.     pid_t pid;  
  7.     int cnt = 0;  
  8.     pid = fork();  
  9.     if(pid<0)  
  10.         printf("error in fork!\n");  
  11.     elseif(pid == 0)  
  12.     {  
  13.         cnt++;  
  14.         printf("cnt=%d\n",cnt);  
  15.         printf("I am the child process,ID is %d\n",getpid());  
  16.     }  
  17.     else
  18.     {  
  19.         cnt++;  
  20.         printf("cnt=%d\n",cnt);  
  21.         printf("I am the parent process,ID is %d\n",getpid());  
  22.     }  
  23.     return 0;  
  24. }  

大家覺著打印出的值應該是多少呢?是不是2 呢?先來看下執行結果吧 

  1. [[email protected] fork]# ./fork2  
  2. cnt=1  
  3. I am the child process,ID is 5077  
  4. cnt=1  
  5. I am the parent process,ID is 5076  

為什麼不是2 呢?因為我們一次強調fork ()函式子程序拷貝父程序的資料段程式碼段,所以 
cnt++; 
    printf("cnt= %d\n",cnt);

    return 0 
將被父子程序各執行一次,但是子程序執行時使自己的資料段裡面的(這個資料段是從父進 
程那copy 過來的一模一樣)count+1,同樣父程序執行時使自己的資料段裡面的count+1, 
他們互不影響,與是便出現瞭如上的結果。


那麼再來看看vfork ()吧。如果將上面程式中的fork ()改成vfork(),執行結果是什麼 
樣子的呢? 

  1. [[email protected] fork]# gcc -o fork3 fork3.c   
  2. [[email protected] fork]# ./fork3  
  3. cnt=1  
  4. I am the child process,ID is 4711  
  5. cnt=1  
  6. I am the parent process,ID is 4710  
  7. 段錯誤  

本來vfock()是共享資料段的,結果應該是2,為什麼不是預想的2 呢?先看一個知識點: 
vfork 和fork 之間的另一個區別是:vfork 保證子程序先執行,在她呼叫exec 或exit 之 
後父程序才可能被排程執行。如果在呼叫這兩個函式之前子程序依賴於父程序的進一步動 
作,則會導致死鎖。 
這樣上面程式中的fork ()改成vfork()後,vfork ()建立子程序並沒有呼叫exec 或exit,
所以最終將導致死鎖。 
怎麼改呢?看下面程式: 

  1. #include<sys/types.h>
  2. #include<unistd.h>
  3. #include<stdio.h>
  4. int main()  
  5. {  
  6.     pid_t pid;  
  7.     int cnt = 0;  
  8.     pid = vfork();  
  9.     if(pid<0)  
  10.         printf("error in fork!\n");  
  11.     elseif(pid == 0)  
  12.     {  
  13.         cnt++;  
  14.         printf("cnt=%d\n",cnt);  
  15.         printf("I am the child process,ID is %d\n",getpid());  
  16.        _exit(0);  
  17.     }  
  18.     else
  19.     {  
  20.         cnt++;  
  21.         printf("cnt=%d\n",cnt);  
  22.         printf("I am the parent process,ID is %d\n",getpid());  
  23.     }  
  24.     return 0;  
  25. }  

如果沒有_exit(0)的話,子程序沒有呼叫exec 或exit,所以父程序是不可能執行的,在子 
程序呼叫exec 或exit 之後父程序才可能被排程執行。 
所以我們加上_exit(0);使得子程序退出,父程序執行,這樣else 後的語句就會被父程序執行, 
又因在子程序呼叫exec 或exit之前與父程序資料是共享的,所以子程序退出後把父程序的數 
據段count改成1 了,子程序退出後,父程序又執行,最終就將count變成了2,看下實際 
執行結果: 

  1. [[email protected]ocalhost fork]# gcc -o fork3 fork3.c   
  2. [[email protected] fork]# ./fork3  
  3. cnt=1  
  4. I am the child process,ID is 4711  
  5. cnt=2  
  6. I am the parent process,ID is 4710  

網上抄的一段,可以再理解理解: 
為什麼會有vfork,因為以前的fork 很傻, 它建立一個子程序時,將會建立一個新的地址 
空間,並且拷貝父程序的資源,而往往在子程序中會執行exec 呼叫,這樣,前面的拷貝工 
作就是白費力氣了,這種情況下,聰明的人就想出了vfork,它產生的子程序剛開始暫時與 
父程序共享地址空間(其實就是執行緒的概念了),因為這時候子程序在父程序的地址空間中 
執行,所以子程序不能進行寫操作,並且在兒子 霸佔”著老子的房子時候,要委屈老子一 
下了,讓他在外面歇著(阻塞),一旦兒子執行了exec 或者exit 後,相 於兒子買了自己的 
房子了,這時候就相 於分家了。

下面給出一個封裝好的my_system

int my_system(const char *cmdstring)
{
pid_t pid;
int status;
int i;
int ret = 0;


if(cmdstring==NULL)
{
return(1);
}


if((pid=vfork())<0)
{
nvr_printf(RED"fork error\n"RESET);
        perror("vfork()");
status=-1;
}
else
{
if(pid == 0)
{
for(i = 0; i < sysconf(_SC_OPEN_MAX); i++)
      {
close(i);
}


ret = execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
perror("execl()");
nvr_printf(GREEN"ret %d error %d\n"RESET, ret, errno);
 _exit(127); //不使用exit是為了保證程序的標準I/O流不被清掉
}
else
{
printf("pid %d\n",pid);
while((ret = waitpid(pid, &status, 0)) < 0)
     if(errno != EINTR)
{
perror("waitpid()");
nvr_printf(RED"ret%d error %d status %d\n"RESET, ret, errno, status);
status=-1; break;
}
}


}


return(status);
}

相關推薦

系統呼叫system失敗原因分析

fork()與vfock()都是建立一個程序,那他們有什麼區別呢?總結有以下三點區別: 1.  fork  ():子程序拷貝父程序的資料段,程式碼段      vfork ( ):子程序與父程序共享資料段 2.  fork ()父子程序的執行次序不確定      vfor

系統技術非業餘研究 » Erlang節點互聯失敗原因分析以及解決方案

今天和項仲在部署新系統的時候發現節點間ping不成功的情況,類似 1> net_adm:ping(‘[email protected]’). pang 由於這個問題比較普遍,我就記錄下一步步的排除步驟. 首先從原理上分析下!由於erlang節點間通訊是透過tcp來進行的,所以我們

CSP平臺銀聯前置系統ATM他帶本和本代他交易失敗原因分析

與銀聯資料中心連線的兩條client端通訊鏈路全部斷開後平臺沒有再重新建立client鏈路與銀聯資料中心通訊(CSP平臺內部機制會在子程序異常退出時再重新拉起新的服務代替異常退出的服務),導致之後所有發往銀聯前置的交易失敗,即ATM他帶本和本代他交易失敗。 1、     

python安裝失敗原因分析(未指定錯誤0x80072efd)

python安裝時間很長,最終報錯未指定錯誤0x80072efd     原因分析: download dubugging symbols download debug binaries 這兩項需要聯網(外網),國內安裝會超時報錯。所以安裝時取消這兩項就

mysql、tomcat、rabbitmq等遠端訪問失敗原因分析

一個伺服器的服務要供遠端主機訪問需要滿足以下幾個條件: 1.遠端使用者有遠端訪問許可權,因為有的服務預設只能本機訪問; 2.使用者名稱或密碼要是正確的; 3.防火牆應開啟對應的埠號,例如:mysq

POST方法給@RequestBody傳引數失敗原因分析

通過ajax給springMVC傳遞引數時,通過post方法傳遞json字串時常用的方式,這時後端應該通過@RequestBody註解配合springMVC中配置的訊息轉換器來進行json字串的解析。 因為post方法中的json字串通常是一個前端的json物件轉化而成的字串,所以後端@Requ

法語德語Windows平臺軟體部署失敗原因分析

在測試過程中,我們時常會遇到軟體在法語、德語的Windows平臺部署失敗的情況,典型錯誤資訊如下: 2016-05-22T16:02:07.768Z (1332,'LookupAccountName

Linux | 系統呼叫System Calls

1 Linux作業系統體系結構 可以把這張圖想象成一個三維的: 最下面的底盤是硬體平臺(Hardware Platform),上面有兩大層:核心區(Kernel Space) 和 使用者區(User space) 其中核心區還有分層 2 系統呼叫

應用在華為P9手機上安裝失敗原因分析 (錯誤碼:-110)

問題描述: 應用在之前的華為手機上都能正常安裝,但是在華為P9手機上安裝失敗,提示錯誤為: 失敗原因: 系統問題導致安裝失敗(錯誤碼:-110) 原因分析: 開始懷疑是android的版本問題,後來看了一下在華為Mate8上面也能正常安裝,華為Mate8和華為P9

騰訊新聞解析失敗原因分析

如圖為騰訊新聞的xml檔案,地址:http://news.qq.com/newsgn/rss_newsgn.xml,原始碼如下:解析方法如下:while (type!=XmlPullParser.END_DOCUMENT){ switch (t

Linux中listen()系統呼叫的backlog引數分析

這篇文章是對上一篇部落格網路程式設計常用介面的核心實現----sys_listen()的補充,上篇文章中我說listen()系統呼叫的backlog引數既是連線佇列的長度,也指定了半連線佇列的長度(不能說等於),而不是《Unix網路程式設計》中講到的是半連線佇列和連線佇列

系統呼叫入口函式原始碼分析system_call——X86_64

在實驗中用到這一塊,就去看原始碼分析整理了一下,全部為個人理解。有錯誤的地方,希望和大牛交流。 首先解釋一下,我實驗的目的是獲得系統呼叫入口函式system_call的起始地址和函式大小。 在linux-3.10.1, x86 64位的系統下,系統呼叫的入口地址儲存在MSR暫存器中,通過rdmsrl(MSR

GTS DefaultPermissionGrantPolicyTest測試失敗原因分析

展訊FAQ95979: 我們在進行Google GTS DefaultPermissionGrantPolicyTest測試時,有時會遇見類似如下的報錯log: failed: testDefaultGrants(com.google.android.xts

HBase跨叢集複製Snapshot失敗原因分析及解決

起因 HBase快照在跨叢集複製時,經常會出現由於/hbase/.tmp/data/xxx FileNotFoundException導致任務失敗  現還原出錯場景,並分析錯誤原因,給出一些常用的解決方法  主要原因  在建立快照到跨叢集複製過程中,部分StoreFil

關於mongodb由於記憶體過小啟動失敗原因分析

今天學習mongodb, ./bin/mongod --dbpath /home/m17 --logpath /home/mlog/m17.log --fork --port 27017 怎麼啟動都不

【linux】系統呼叫版串列埠分析&原始碼實戰

[toc] --- ## 前言 * **目前不涉及驅動原始碼** ## 參考 * [linux手冊之termios](https://man7.org/linux/man-pages/man3/termios.3.html) * [本文連結](https://www.cnblogs.com/lizhu

Android 4.X 系統加載 so 失敗原因分析

tabs mod ext 問題 用戶 統計數據 crash 情況 text 1 so 加載過程 so 加載的過程可以參考小米的系統工程師的文章loadLibrary動態庫加載過程分析 2 問題分析 2.1 問題 年前項目裏新加了一個 so庫,但發現native 方法的找不到

Android呼叫系統照相機返回intent為空原因分析

1.在呼叫android系統相簿時,使用的是如下方式:     Intent intent = new Intent(Intent.ACTION_GET_CONTENT);             intent.addCategory(Intent.CATEGORY_OPE

Servlet 服務器啟動失敗原因分析

解決 context tomcat c11 onf www. 文件夾 fail eclips Server Tomcat v7.0 Server at localhost failed to start. 可能錯誤分析剛入門學習java Web的相關知識 ,啟動服務器出現我

fiddler在ios10.3系統抓包https失敗原因解決

開啟 afa apple 抓包 img enter 代理ip 安裝 名單 一直是按照以往的設置抓包,設置代理ip,通過Safari下載安裝證書,抓包https怎麽顯示證書無效呢?難道證書被apple設為黑名單了?google後發現,IOS10.3以後,安裝了證書不是默認啟用