關於linux多執行緒fork的理解和學習

dxhua發表於2022-05-14
  fork在英文中是“分叉”的意思。為什麼取這個名字呢?因為一個程式在執行中,如果使用了fork函式,就產生了另一個程式,於是程式就“分叉”了,所以這個名字取得很形象。下面就看看如何具體使用fork函式,這段程式演示了使用fork的基本框架。
 
函式宣告:
 
pid_t fork();
 
  fork函式用於產生一個新的程式,函式返回值pid_t是一個整數,在父程式中,返回值是子程式編號,在子程式中,返回值是0。
 
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
 
int main()
{
  printf("本程式的程式編號是:%d\n",getpid());
 
  int ipid=fork();
 
  sleep(1);       // sleep等待程式的生成。
 
  printf("pid=%d\n",ipid);
 
  if (ipid!=0) printf("父程式編號是:%d\n",getpid());
  else printf("子程式編號是:%d\n",getpid());
 
  sleep(30);    // 是為了方便檢視程式在shell下用ps -ef|grep book252檢視本程式的編號。
}
   
從 fork() 這個函式開始出現後,
便建立了子程式,並且子程式和父程式一樣從fork(這個函式一起執行下去,也就是說從fork()開始的下面所有程式碼分別被父
程式和子程式都執行了一次,如果沒有條件判斷語句判別fork()的返回值,將無法分別子父程式,根據fork()的返回值可以令子父程式跳過或執行某條語句

執行結果

 

 

初學者可能用點接受不了現實。

1)一個函式(fork)返回了兩個值?

2)if和else中的程式碼能同時被執行?

那麼呼叫這個fork函式時發生了什麼呢?fork函式建立了一個新的程式,新程式(子程式)與原有的程式(父程式)一模一樣。子程式和父程式使用相同的程式碼段;子程式拷貝了父程式的堆疊段和資料段。子程式一旦開始執行,它複製了父程式的一切資料,然後各自執行,相互之間沒有影響。

fork函式對返回值做了特別的處理,呼叫fork函式之後,在子程式中fork的返回值是0,在父程式中fork的返回是子程式的編號,程式設計師可以通過fork的返回值來區分父程式和子程式,然後再執行不同的程式碼。

 

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

void fatchfunc() // 父程式流程的主函式
{
  printf("我是老子,我喜歡孩子他娘。\n");
}

void childfunc() // 子程式流程的主函式
{
  printf("我是兒子,我喜歡西施。\n");
}

int main()
{
  if (fork() > 0)
  {
    printf("這是父程式,將呼叫fatchfunc()。\n");
    fatchfunc();
  }
  else
  {
    printf("這是子程式,將呼叫childfunc()。\n");
    childfunc();
  }

  sleep(1);
  printf("父子程式執行完自己的函式後都來這裡。\n");
  sleep(1);
}

 

 

執行結果:

 

 

在上文上已提到過,子程式拷貝了父程式的堆疊段和資料段,也就是說,在父程式中定義的變數子程式中會複製一個副本,fork之後,子程式對變數的操作不會影響父程式,父程式對變數的操作也不會影響子程式。

 

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
 
int i=10;
 
int main()
{
  int j=20;
 
  if (fork()>0)  //從 fork() 這個函式開始出現後,
                  //便建立了子程式並且和父程式一樣從fork()
                  //這個函式一起執行下去,也就是說從fork()開始的下面所有程式碼分別被父///程式和子程式都執行了一次,如果沒有條件判斷語句判別fork()的返回/////值,將無法分別子父程式,根據fork()的返回值可以令子父程式跳過或執///行某條語句

  {
    //如果fork大於零,證明是父程式,即執行下面的語句
    
    i=11;j=1; sleep(1);  printf("父程式:i=%d,j=%d\n",i,j);
    int sum = i + j;
    printf("父sum = %d\n",sum);

  }
  else
  {
    //如果fork小於零,證明是子程式,執行下面的語句
    i=12;j=22; sleep(1);  printf("子程式:i=%d,j=%d\n",i,j);
    printf("子sum = %d\n",i+j);

  }
}
 
 
從 fork() 這個函式開始出現後,便建立了子程式,並且子程式和父程式一樣從fork(這個函式一起執行下去,也就是說從fork()開始的下面所有程式碼分別被父
程式和子程式都執行了一次,如果沒有條件判斷語句判別fork()的返回值,將無法分別子父程式,根據fork()的返回值可以令子父程式跳過或執行某條語句

執行結果

 

 

 

 

來源:www.freecplus.net

作者:碼農有道

 

作業:

(1)編寫一個多程式程式,驗證子程式是複製父程式的記憶體變數,還是父子程式共享記憶體變數?

 

複製記憶體變數

 

 

 

2)編寫一個示例程式,由父程式生成10個子程式,在子程式中顯示它是第幾個子程式和子程式本身的程式編號。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
  int i = 0;
  while (i < 10)
  {

    if (fork() > 0) 
    {
      i++;
      continue; //父程式回到while(迴圈),
    }
    else
    {
      printf("子程式第%d個,pid = %d\n", i, getpid());
      break;
    }
  }
  sleep(10);

  return 0;
}

 

執行結果

 

 

 

 

 

 

3)編寫示例程式,由父程式生成子程式,子程式再生成孫程式,共生成第10代程式,在各級子程式中顯示它是第幾代子程式和子程式本身的程式編號。

 

如圖

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
  int i = 0; //全域性變數,計數器,計算第幾代子程式
  while (i < 10)
  {

    if (fork()== 0)
    {
      i++;
      continue;
    }
    else
    {
      printf("第%d代子程式,pid = %d\n", i, getpid()); 第 0 代子程式是第一個父程式
    
      break;
    }
  }
  sleep(10);

  return 0;
}

 

執行結果:

子程式是下一個子程式的父程式

 

 

 

4)利用盡可能少的程式碼快速fork出更多的程式,試試看能不能把linux系統搞死。

 

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
  int i = 0; //全域性變數,計數器,計算第幾代子程式
  while (i < 10)
  {

    if (fork()>0)
    {
      fork();
      
    
      
    }
  }
  printf("pid=%d",getpid());

  return 0;
}

 

 

 

 

 

5)ps -ef |grep book251命令是ps和grep兩個系統命令的組合,各位查一下資料,瞭解一下grep命令的功能,對程式設計師來,grep是經常用到的命令。

 

 https://blog.csdn.net/weixin_52273136/article/details/110451596

 

 

來源:C語言技術網(www.freecplus.net

作者:碼農有道

 

 

相關文章