Tạo và kết thúc quy trình

Cho đến bây giờ chúng ta biết rằng bất cứ khi nào chúng ta thực thi một chương trình thì một quá trình sẽ được tạo ra và sẽ được kết thúc sau khi hoàn thành việc thực thi. Điều gì sẽ xảy ra nếu chúng ta cần tạo một quy trình trong chương trình và có thể muốn lên lịch một nhiệm vụ khác cho nó. Điều này có thể đạt được không? Có, rõ ràng là thông qua quá trình tạo. Tất nhiên, sau khi hoàn thành công việc, nó sẽ tự động kết thúc hoặc bạn có thể chấm dứt nó nếu cần.

Quá trình tạo ra được thực hiện thông qua fork() system call. Quá trình mới được tạo ra được gọi là quá trình con và quá trình khởi tạo nó (hoặc quá trình khi bắt đầu thực thi) được gọi là quá trình mẹ. Sau lời gọi hệ thống fork (), bây giờ chúng ta có hai quy trình - quy trình mẹ và quy trình con. Làm thế nào để phân biệt chúng? Rất đơn giản, đó là thông qua các giá trị trả về của chúng.

Sau khi tạo tiến trình con, chúng ta hãy xem chi tiết cuộc gọi hệ thống fork ().

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

pid_t fork(void);

Tạo quy trình con. Sau cuộc gọi này, có hai tiến trình, tiến trình hiện có được gọi là quy trình mẹ và quy trình mới được tạo ra được gọi là quy trình con.

Lệnh gọi hệ thống fork () trả về một trong ba giá trị:

  • Giá trị âm để chỉ ra lỗi, tức là không thành công trong việc tạo quy trình con.

  • Trả về số 0 cho tiến trình con.

  • Trả về giá trị dương cho tiến trình mẹ. Giá trị này là ID tiến trình của tiến trình con mới được tạo.

Chúng ta hãy xem xét một chương trình đơn giản.

File name: basicfork.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
   fork();
   printf("Called fork() system call\n");
   return 0;
}

Các bước thực hiện

Tổng hợp

gcc basicfork.c -o basicfork

Thực thi / Đầu ra

Called fork() system call
Called fork() system call

Note- Thông thường sau khi gọi fork (), process con và process cha sẽ thực hiện các nhiệm vụ khác nhau. Nếu cùng một tác vụ cần được chạy, thì với mỗi lệnh fork (), nó sẽ chạy 2 lần n lần, trong đón là số lần fork () được gọi.

Trong trường hợp trên, fork () được gọi một lần, do đó đầu ra được in hai lần (2 lũy thừa 1). Nếu fork () được gọi, giả sử 3 lần, thì đầu ra sẽ được in 8 lần (2 lũy thừa 3). Nếu nó được gọi là 5 lần, thì nó sẽ in 32 lần, vân vân và vân vân.

Sau khi thấy fork () tạo quy trình con, đây là lúc để xem chi tiết của các quy trình cha và con.

Tên tệp: pids_ after_fork.c

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

int main() {
   pid_t pid, mypid, myppid;
   pid = getpid();
   printf("Before fork: Process id is %d\n", pid);
   pid = fork();

   if (pid < 0) {
      perror("fork() failure\n");
      return 1;
   }

   // Child process
   if (pid == 0) {
      printf("This is child process\n");
      mypid = getpid();
      myppid = getppid();
      printf("Process id is %d and PPID is %d\n", mypid, myppid);
   } else { // Parent process 
      sleep(2);
      printf("This is parent process\n");
      mypid = getpid();
      myppid = getppid();
      printf("Process id is %d and PPID is %d\n", mypid, myppid);
      printf("Newly created process id or child pid is %d\n", pid);
   }
   return 0;
}

Các bước biên dịch và thực hiện

Before fork: Process id is 166629
This is child process
Process id is 166630 and PPID is 166629
Before fork: Process id is 166629
This is parent process
Process id is 166629 and PPID is 166628
Newly created process id or child pid is 166630

Một quá trình có thể kết thúc theo một trong hai cách sau:

  • Bất thường, xảy ra khi phát một số tín hiệu nhất định, chẳng hạn như tín hiệu kết thúc.

  • Thông thường, sử dụng lệnh gọi hệ thống _exit () (hoặc lệnh gọi hệ thống _Exit ()) hoặc hàm thư viện exit ().

Sự khác biệt giữa _exit () và exit () chủ yếu là hoạt động dọn dẹp. Cácexit() thực hiện một số dọn dẹp trước khi trả lại điều khiển trở lại hạt nhân, trong khi _exit() (hoặc _Exit ()) sẽ trả lại điều khiển trở lại hạt nhân ngay lập tức.

Hãy xem xét chương trình ví dụ sau với exit ().

Tên tệp: atexit_sample.c

#include <stdio.h>
#include <stdlib.h>

void exitfunc() {
   printf("Called cleanup function - exitfunc()\n");
   return;
}

int main() {
   atexit(exitfunc);
   printf("Hello, World!\n");
   exit (0);
}

Các bước biên dịch và thực hiện

Hello, World!
Called cleanup function - exitfunc()

Hãy xem xét chương trình ví dụ sau với _exit ().

Tên tệp: at_exit_sample.c

#include <stdio.h>
#include <unistd.h>

void exitfunc() {
   printf("Called cleanup function - exitfunc()\n");
   return;
}

int main() {
   atexit(exitfunc);
   printf("Hello, World!\n");
   _exit (0);
}

Các bước biên dịch và thực hiện

Hello, World!