create的固定搭配,create的各種形式

fork

fork 函數創建子進程成功後,父進程返回子進程的 pid,子進程返回0。具體描述如下:

  • fork返回值為-1, 代表創建子進程失敗
  • fork返回值為0,代表子進程創建成功,這個分支是子進程的運行邏輯
  • fork返回值大於0,這個分支是父進程的運行邏輯,並且返回值等於子進程的 pid

我們看下通過 fork 系統調用來創建子進程的例子:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
 
int main()
{
   pid_t pid = fork();
 
   if(pid == -1){
       printf("create child process failed!n");
       return -1;
   }else if(pid == 0){
       printf("This is child process!n");
   }else{
       printf("This is parent process!n");
       printf("parent process pid = %dn",getpid());
       printf("child process pid = %dn",pid);
   }
 
   getchar();
 
   return 0;
}

運行結果:

$ ./a.out
This is parent process!
parent process pid = 25483
child process pid = 25484
This is child process!

從上面的運行結果來看,子進程的pid=25484, 父進程的pid=25483。

在前面介紹內存缺頁異常的時候,提到寫時複製 COW 是一種推遲或者避免複製數據的技術,主要用在 fork 系統調用里,當執行 fork 創建新子進程時,內核不需要複製父進程的整個進程地址空間給子進程,而是讓父進程和子進程共享同一個副本,只有寫入時,數據才會被複制。我們用一個簡單里的例子描述下:

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

int peter = 10;

int main()
{
  pid_t pid = fork();

  if(pid == -1){
      printf("create child process failed!n");
      return -1;
  }else if(pid == 0){
      printf("This is child process, peter = %d!n", peter);
      peter = 100;
      printf("After child process modify peter = %dn", peter);
  }else{
      printf("This is parent process = %d!n", peter);
  }

  getchar();

  return 0;
}

執行結果:

$ ./a.out
This is parent process = 10!
This is child process, peter = 10!
After child process modify peter = 100

從運行結果可以看到,不論子進程如何去修改 peter 的值,父進程永遠看到的是自己的那一份。

用戶態進程/線程的創建 fork/vfork/pthread_create

vfork

接下來看下使用 vfork 來創建子進程:

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

int peter = 10;

int main()
{
  pid_t pid = vfork();

  if(pid == -1){
      printf("create child process failed!n");
      return -1;
  }else if(pid == 0){
      printf("This is child process, peter = %d!n", peter);
      peter = 100;
      printf("After child process modify peter = %dn", peter);
      exit(0);
  }else{
      printf("This is parent process = %d!n", peter);
  }

  getchar();

  return 0;
}

運行結果:

$ ./a.out
This is child process, peter = 10!
After child process modify peter = 100
This is parent process = 100!

從運行結果中可以看出,當子進程修改了 peter=100 之後,父進程中打印 peter 的值也是100。

用戶態進程/線程的創建 fork/vfork/pthread_create

C/C++Linux服務器開發/後台架構師【零聲教育】-學習視頻教程-騰訊課堂

【文章福利】:小編整理了一些個人覺得比較好的學習書籍、視頻資料共享在群文件裏面,有需要的可以自行添加哦!~點擊加入(832218493需要自取)

用戶態進程/線程的創建 fork/vfork/pthread_create

pthread_create

現在我們知道了創建進程有兩種方式:fork,vfork。那麼創建線程呢?

線程的創建接口是用 pthread_create:

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

int peter = 10;

static pid_t gettid(void)
{
 return syscall(SYS_gettid);
}

static void* thread_call(void* arg)
{
 peter = 100;
 printf("create thread success!n");
 printf("thread_call pid = %d, tid = %d, peter = %dn", getpid(), gettid(), peter);
 return NULL;
}

int main()
{
 int ret;
 pthread_t thread;

 ret = pthread_create(&thread, NULL, thread_call, NULL);
 if(ret == -1)
     printf("create thread faild!n");

 ret = pthread_join(thread, NULL);
 if(ret == -1)
     printf("pthread join failed!n");

 printf("process pid = %d, tid = %d, peter = %dn", getpid(), gettid(), peter);

 return ret;
}

運行結果:

$ ./a.out
create thread success!
thread_call pid = 9719, tid = 9720, peter = 100
process pid = 9719, tid = 9719, peter = 100

從上面的結果可以看出:進程和線程的 pid 都是相同的。當線程修改了 peter = 100 之後,父進程中打印 peter 的值也是100。

用戶態進程/線程的創建 fork/vfork/pthread_create

進程線程創建總圖

上面介紹了用戶態創建進程和線程的方式,以及各個方式的特點。關於其底層的實現本質,我們後面會詳細講解。這裡先提供一下三者之間的關係,可見三者最終都會調用 do_fork 實現。

用戶態進程/線程的創建 fork/vfork/pthread_create

但是內核態沒有進程線程的概念,內核中只認 task_struct 結構,只要是 task_struct 結構就可以參與調度。

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/230991.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
投稿專員的頭像投稿專員
上一篇 2024-12-10 18:45
下一篇 2024-12-10 18:45

相關推薦

發表回復

登錄後才能評論