進階Linux程式設計第三章:進程

來源:互聯網
上載者:User
文章目錄
  • 每個進程都有一個唯一的進程號。
  • 每個進程都有一個父進程。
  • 系統中的進程以樹的形式組織,init進程(進程號為1)作為根。
  • 進程0是調度進程,沒有程式與之對應,是核心的一部分。
  • 進程1是init進程,是在系統啟動的階段由核心啟動的,對應/sbin/init程式,是普通的使用者進程。
  • 程式中可以通過getpid()得到進程號,通過getppid()得到父進程的進程號。
  • 通過ps命令可以得到系統中啟動並執行所有進程。
  • 通過kill命令可以殺掉某個進程。
  • system函數提供了一種在程式中運行一個命令的簡單方法。
  • 當程式調用fork的時候,則一個完全複製的子程式被建立。
  • 父進程將從fork被調用的地方繼續執行下去。
  • 子進程也是從相同的地方運行下去。
  • 父進程中fork函數的傳回值是子進程的進程號。
  • 子進程中fork函數的傳回值是零。
  • exec函數將當前啟動並執行進程替換為另一個程式。
  • exec函數是一組函數:
  • 包含p的函數(execvp, execlp)接收的參數是程式名。
  • 不包含p的函數接收的參數是程式的全路徑。
  • 包含v的函數(execv, execvp, execve)以數組的形式接收參數列表。
  • 包含l的函數(execl, execlp, execle)以列舉的形式接收參數列表。
  • 包含e的函數(execve, execle)以數組的形式接收環境變數。
  • 訊號是發送給進程的特殊資訊。
  • 當一個進程接收到一個訊號的時候,它會立即處理此訊號,並不等待完成當前的函數調用甚至當前一行代碼。
  • 系統會在特殊情況下向進程發送訊號:
  • SIGBUS:匯流排錯誤
  • SIGSEGV:段違規
  • SIGFPE:浮點數異常
  • 一個進程可以向另一個進程發送訊號。
  • 可以發送SIGTERM和SIGKILL訊號來結束一個進程。
  • 訊號可以用來向一個進程發送命令。有兩種使用者自訂訊號:SIGUSER1和SIGUSR2
  • sigaction函數設定訊號處理方式
  • SIG_DFL表示使用預設的訊號處理方式。
  • SIG_IGN表示此訊號可以被忽略。
  • 第二個參數是sigaction結構體,其包括一個訊號處理函數。
  • 由於訊號處理是非同步,因而在訊號處理函數中不要調用I/O操作,也不要調用庫或者系統的函數。
  • 訊號處理函數中應該盡量處理最少的東西。
  • 訊號處理函數也可能被另一個訊號中斷。
  • 如果在訊號處理函數中期望對一個全域變數進行操作,此變數應該是sig_atomic_t類型。
  • 一個進程可以有兩種方式結束:
  • 進程本身調用exit函數,或者其main函數結束。
  • 進程接收到訊號後異常結束。
  • ctrl+c發送SIGINT訊號
  • kill命令發送SIGTERM訊號
  • abort函數發送SIGABRT訊號
  • SIGKILL函數會立即結束一個進程,此訊號不能被阻止,被程式自己處理。
  • 所有這些訊號都可以用kill命令發送
  • 用kill函數可以在程式中向一個進程發送訊號。
  • 有關wait函數:
  • wait函數阻止當前的進程,直到其中一個子進程結束。
  • waitpid函數等待一個指定的子進程結束。
  • wait3函數等待子進程結束並返回子進程的各種資源使用的統計。
  • wait4函數等待特定的子進程結束並返回子進程的各種資源使用的統計。
  • 所謂僵死的進程指的是一個進程結束了但資源尚未被回收。
  • 父進程有責任在子進程結束的時候用wait函數回收子進程的資源。
  • 在子進程尚未被父進程回收的時候,其在系統中作為僵死進程存在。
  • 當一個程式結束的時候,其所有的子進程都被一個特殊的進程(init進程)繼承。init進程負責回收所有它繼承過來的僵死的子進程。
  • 當一個子進程結束的時候,將對其父進程發送SIGCHID訊號。
  • 一個進程可以通過處理SIGCHID訊號來回收子進程。
  • 每個進程都有一個唯一的進程號。
  • 每個進程都有一個父進程。
  • 系統中的進程以樹的形式組織,init進程(進程號為1)作為根。
    • 進程0是調度進程,沒有程式與之對應,是核心的一部分。
    • 進程1是init進程,是在系統啟動的階段由核心啟動的,對應/sbin/init程式,是普通的使用者進程。
  • 程式中可以通過getpid()得到進程號,通過getppid()得到父進程的進程號。

 

#include <stdio.h>

#include <unistd.h>

int main ()

{

    printf (“The process ID is %d\n”, (int) getpid ());

    printf (“The parent process ID is %d\n”, (int) getppid ());

    return 0;

}

  • 通過ps命令可以得到系統中啟動並執行所有進程。
  • 通過kill命令可以殺掉某個進程。
1、建立進程1.1、system函數
  • system函數提供了一種在程式中運行一個命令的簡單方法。

 

#include <stdlib.h>

int main ()

{

    int return_value;

    return_value = system (“ls -l /”);

    return return_value;

}

1.2、fork及exec函數
  • 當程式調用fork的時候,則一個完全複製的子程式被建立。
  • 父進程將從fork被調用的地方繼續執行下去。
  • 子進程也是從相同的地方運行下去。
  • 父進程中fork函數的傳回值是子進程的進程號。
  • 子進程中fork函數的傳回值是零。

#include <stdio.h>

#include <sys/types.h>

#include <unistd.h>

int main ()

{

    pid_t child_pid;

    printf (“the main program process ID is %d\n”, (int) getpid ());

    child_pid = fork ();

    if (child_pid != 0) {

        printf (“this is the parent process, with id %d\n”, (int) getpid ());

        printf (“the child’s process ID is %d\n”, (int) child_pid);

    }

    else

        printf (“this is the child process, with id %d\n”, (int) getpid ());

    return 0;

}

  • exec函數將當前啟動並執行進程替換為另一個程式。
  • exec函數是一組函數:
    • 包含p的函數(execvp, execlp)接收的參數是程式名。
    • 不包含p的函數接收的參數是程式的全路徑。
    • 包含v的函數(execv, execvp, execve)以數組的形式接收參數列表。
    • 包含l的函數(execl, execlp, execle)以列舉的形式接收參數列表。
    • 包含e的函數(execve, execle)以數組的形式接收環境變數。

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <unistd.h>

/* Spawn a child process running a new program. PROGRAM is the name of the program to run; the path will be searched for this program. ARG_LIST is a NULL-terminated list of character strings to be passed as the program’s argument list. Returns the process ID of the spawned process. */

int spawn (char* program, char** arg_list)

{

    pid_t child_pid;

    /* Duplicate this process. */

    child_pid = fork ();

    if (child_pid != 0)

    /* This is the parent process. */

        return child_pid;

    else {

        /* Now execute PROGRAM, searching for it in the path. */

        execvp (program, arg_list);

        /* The execvp function returns only if an error occurs. */

        fprintf (stderr, “an error occurred in execvp\n”);

        abort ();

    }

}

int main ()

{

    /* The argument list to pass to the “ls” command. */

    char* arg_list[] = {

        “ls”, /* argv[0], the name of the program. */

        “-l”,

        “/”,

        NULL /* The argument list must end with a NULL. */

    };

    /* Spawn a child process running the “ls” command. Ignore the returned child process ID. */

    spawn (“ls”, arg_list);

    printf (“done with main program\n”);

    return 0;

}

 

2、訊號
  • 訊號是發送給進程的特殊資訊。
  • 當一個進程接收到一個訊號的時候,它會立即處理此訊號,並不等待完成當前的函數調用甚至當前一行代碼。
  • 系統會在特殊情況下向進程發送訊號:
    • SIGBUS:匯流排錯誤
    • SIGSEGV:段違規
    • SIGFPE:浮點數異常
  • 一個進程可以向另一個進程發送訊號。
  • 可以發送SIGTERM和SIGKILL訊號來結束一個進程。
  • 訊號可以用來向一個進程發送命令。有兩種使用者自訂訊號:SIGUSER1和SIGUSR2
  • sigaction函數設定訊號處理方式
    • SIG_DFL表示使用預設的訊號處理方式。
    • SIG_IGN表示此訊號可以被忽略。
    • 第二個參數是sigaction結構體,其包括一個訊號處理函數。
  • 由於訊號處理是非同步,因而在訊號處理函數中不要調用I/O操作,也不要調用庫或者系統的函數。
  • 訊號處理函數中應該盡量處理最少的東西。
  • 訊號處理函數也可能被另一個訊號中斷。
  • 如果在訊號處理函數中期望對一個全域變數進行操作,此變數應該是sig_atomic_t類型。

#include <stdio.h>

#include <signal.h>

#include <string.h>

#include <sys/types.h>

#include <unistd.h>

sig_atomic_t sigusr1_count = 0;

void handler(int signal_number)

{

++sigusr1_count;

}

int main(int argc, char* argv[])

{

    printf("the process ID is %d\n", (int)getpid());

    struct sigaction sa;

    memset(&sa, 0, sizeof(sa));

    sa.sa_handler = &handler;

    sigaction(SIGUSR1, &sa, NULL);

    int i = 0;

    while(i < 100)

    {

        sleep(1);

        i++;

    }

    printf("SIGUSR was raised %d times\n", sigusr1_count);

    return 0;

}

編譯上述代碼為程式sigusr1

gcc -o sigusr1 sigusr1.c

運行程式

[liuchao@localhost Signal]$ ./sigusr1

the process ID is 3401

在另一個終端,用ps命令得到sigusr1的進程號

[liuchao@localhost ~]$ ps -a

PID TTY TIME CMD

3401 pts/1 00:00:00 sigusr1

3403 pts/3 00:00:00 ps

向此進程號發送多個sigusr1訊號

[liuchao@localhost ~]$ kill -s SIGUSR1 3401

[liuchao@localhost ~]$ kill -s SIGUSR1 3401

[liuchao@localhost ~]$ kill -s SIGUSR1 3401

[liuchao@localhost ~]$ kill -s SIGUSR1 3401

[liuchao@localhost ~]$ kill -s SIGUSR1 3401

當進程結束後

[liuchao@localhost Signal]$ ./sigusr1

the process ID is 3401

SIGUSR was raised 5 times

 

3、結束進程
  • 一個進程可以有兩種方式結束:
    • 進程本身調用exit函數,或者其main函數結束。
    • 進程接收到訊號後異常結束。
      • ctrl+c發送SIGINT訊號
      • kill命令發送SIGTERM訊號
      • abort函數發送SIGABRT訊號
      • SIGKILL函數會立即結束一個進程,此訊號不能被阻止,被程式自己處理。
  • 所有這些訊號都可以用kill命令發送

 

% kill -KILL pid
  • 用kill函數可以在程式中向一個進程發送訊號。
kill (child_pid, SIGTERM);
  • 有關wait函數:
    • wait函數阻止當前的進程,直到其中一個子進程結束。
    • waitpid函數等待一個指定的子進程結束。
    • wait3函數等待子進程結束並返回子進程的各種資源使用的統計。
    • wait4函數等待特定的子進程結束並返回子進程的各種資源使用的統計。

int main ()

{

    int child_status;

    /* The argument list to pass to the “ls” command. */

    char* arg_list[] = {

        “ls”, /* argv[0], the name of the program. */

        “-l”,

        “/”,

        NULL /* The argument list must end with a NULL. */

    };

    /* Spawn a child process running the “ls” command. Ignore the returned child process ID. */

    spawn (“ls”, arg_list);

    /* Wait for the child process to complete. */

    wait (&child_status);

    if (WIFEXITED (child_status))

        printf (“the child process exited normally, with exit code %d\n”, WEXITSTATUS (child_status));

    else

        printf (“the child process exited abnormally\n”);

    return 0;

}

  • 所謂僵死的進程指的是一個進程結束了但資源尚未被回收。
  • 父進程有責任在子進程結束的時候用wait函數回收子進程的資源。
  • 在子進程尚未被父進程回收的時候,其在系統中作為僵死進程存在。

#include <stdlib.h>

#include <sys/types.h>

#include <unistd.h>

int main ()

{

    pid_t child_pid;

    /* Create a child process. */

    child_pid = fork ();

    if (child_pid > 0) {

        /* This is the parent process. Sleep for a minute. */

       sleep (60);

    }

    else {

        /* This is the child process. Exit immediately. */

        exit (0);

    }

    return 0;

}

% ps -e -o pid,ppid,stat,cmd

3824 2888 S+ ./zombie

3825 3824 Z+ [zombie] <defunct>

  • 當一個程式結束的時候,其所有的子進程都被一個特殊的進程(init進程)繼承。init進程負責回收所有它繼承過來的僵死的子進程。
  • 當一個子進程結束的時候,將對其父進程發送SIGCHID訊號。
  • 一個進程可以通過處理SIGCHID訊號來回收子進程。

#include <signal.h>

#include <string.h>

#include <sys/types.h>

#include <sys/wait.h>

sig_atomic_t child_exit_status;

void clean_up_child_process (int signal_number)

{

    /* Clean up the child process. */

    int status;

    wait (&status);

    /* Store its exit status in a global variable. */

    child_exit_status = status;

}

int main ()

{

    /* Handle SIGCHLD by calling clean_up_child_process. */

    struct sigaction sigchld_action;

    memset (&sigchld_action, 0, sizeof (sigchld_action));

    sigchld_action.sa_handler = &clean_up_child_process;

    sigaction (SIGCHLD, &sigchld_action, NULL);

    /* Now do things, including forking a child process. */

    /* ... */

    return 0;

}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.