Linux-C-Day3-進程

進程

  • fork

進程複製,子進程依賴父進程執行時長

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

int main(void) {
    pid_t pid;
    char *message;

    pid = fork();
    if (pid < 0) {
        perror("fork failed");
        exit(1);
    }
    // pid = 0; 子線程
    if (pid == 0) {
        // 如果主進程先執行完畢,子進程會提前退出
        message = "This is child process \n";
        sleep(1);
    } else {
        message = "This is the parent \n ";
        sleep(3);
    }

    printf("%s\n", message);
    return 0;
}

執行應用命令

  • execlp
  • execvp
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

/**
 * execlp(), execvp() 會替代當前進程代碼,執行後直接結束
 * p: path
 * 第一個參數: 執行文件path
 * 第二個參數(s): 代表 argv[0], argv[1]... , 所以第一個argv, 是要和執行文件同名
 * 最後一個參數以 NULL 結束
 *
 */
int main(void) {

    // 知道全部參數的場景下
    execlp("/usr/local/bin/oss", "oss", "ls", NULL);

    // 以參數數組的形式傳進來
    char *cmd = "/usr/local/bin/oss";
    char *args[] = {"oss", "ls", NULL};
    execvp(cmd, args);

    // 正常情況下,不會執行到這裏, 除非上面出錯。
    perror("exec error");
    exit(1);
}

管道支持

  • getchar
  • putchar
  • toupper
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>

/**
 * 利用特性:exec結束後,原來的文件fd保持打開狀態
 * 利用這個機制,可以編寫管道程序
 */
int main(void) {
    int ch;
    // EOF : Ctrl-D 退出
    while((ch = getchar()) != EOF) {
        putchar(toupper(ch));
    }
    return 0;
}

應用內執行外部文件

  • fputs
  • dup2
  • execl
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>

/**
 * 把參數文件在程序內部調用 upper 方法
 */
int main(int argc, char *argv[]) {
    int fd;
    if (argc != 2) {
        fputs("usage: wrapper file\n", stderr);
        exit(1);
    }
    // 只讀打開文件
    fd = open(argv[1], O_RDONLY);
    if (fd < 0) {
        perror("open");
        exit(1);
    }

    // 把外部文件fd, 複製給 標準輸入fd
    dup2(fd, STDIN_FILENO);
    // 關閉原來的文件fd
    close(fd);

    // 執行外部應用,它會從標準輸入讀取信息
    execl("./upper", "upper", NULL);
    perror("exec ./upper");
    exit(1);
}

殭屍進程

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>


/**
 * 錯誤示例:主進程不結束,生成殭屍進程。
 * 主進程狀態: ps u 的狀態爲 Z.
 * 此時是無法kill -9 的方法殺掉。
 */
int main(void) {
    pid_t pid = fork();
    if (pid < 0) {
        perror("fork");
        exit(1);
    }

    if (pid > 0) {
        while (1);
    }

    return 0;
}

進程同步

  • waitpid
  • getpid
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>

int main(void) {
    pid_t pid;
    pid = fork();
    if (pid < 0) {
        perror("fork failed:");
        exit(1);
    }
    if (pid == 0) {
        int i;
        for (i = 3; i > 0; i--) {
            printf("This is the child\n");
            sleep(1);
        }
        exit(3);
    } else {
        int stat_val;
        // getpid(): 當前進程id
        // pid : 子線程id
        printf("current pid : %d,  child pid : %d\n", getpid(), pid);

        // 等待子進程結束
        waitpid(pid, &stat_val, 0);

        // 如果子進程以 exit()方式結束,獲取其值。
        if (WIFEXITED(stat_val))
            printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
        else if (WIFSIGNALED(stat_val)) // 以中斷等方式退出的,走進這裏
            printf("Child terminated abnormally, signal %d\n", WTERMSIG(stat_val));
    }
    return 0;
}

進程同信-IPC

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>


#define MAXLINE 80

/**
 * 進程間通信: IPC (InterProcess Communication)
 * pipe(fd[2]) 創建一個管道, fd[0]: 讀端,  fd[1]: 寫端
 */
int main(void) {
    ssize_t n;
    int fd[2];
    pid_t pid;
    char line[MAXLINE];

    if (pipe(fd) < 0) {
        perror("pipe");
        exit(1);
    }

    if ((pid = fork()) < 0) {
        perror("fork");
        exit(1);
    }

    if (pid > 0) { /* 主進程 */
        /**
         * 主進程只管寫,所以先關閉 讀端 ?
         */
        close(fd[0]);
        char *msg = "hello world\n";
        write(fd[1], msg, strlen(msg));
        // 寫入寫端後,等待子進程結束
        wait(NULL);
    } else { /* 子進程 */
        /**
         * 先關閉寫端
         */
        close(fd[1]);
        // 從讀端讀取一行
        n = read(fd[0], line, MAXLINE);
        // 打印到標準輸出
        write(STDOUT_FILENO, line, n);
    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章