Linux系统编程-进程

1. 进程ID

  • 每个进程都有一个非负整型表示的唯一进程ID
  • 进程ID唯一,但进程终止后进程ID可复用
    在这里插入图片描述
#include <stdio.h>
#include <unistd.h>

int main() {
    int pid = getpid();
    printf("pid = %d\n", pid);
    int uid = getuid();
    printf("uid = %d\n", uid);
    return 0;
}

2. 创建进程 (fork)

#include <unistd.h>

pid_t fork(void);
  • 调用成功返回两次
  • 子进程返回0,父进程返回子进程ID
  • 失败返回-1

fork创建进程会复制父进程存储空间,有全拷贝和写时拷贝(子进程使用父进程中数据时才拷贝)

  1#include <stdio.h>
  2 #include <unistd.h>
  3
  4 int main()
  5 {
  6     pid_t pid;
  7
  8     printf("parent id = %d\n", getpid());
  9
 10     pid = fork();	// fork后的代码父子进程都执行
 11     if (pid > 0)
 12     {
 13         printf("this parent, pid = %d\n", getpid());
 14     }
 15     if (pid == 0)
 16     {
 17         printf("this child, pid = %d\n", getpid());
 18     }
 19
 20     return 0;
 21 }

输出:

parent id = 17277
this parent, pid = 17277
this child, pid = 17278

3. 使用vfork 创建进程

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

 pid_t vfork(void);

与fork 区别:

  • vfork直接使用父进程存储空间,不拷贝
  • vfork 保证子进程先运行,当子进程调用exit退出后,父进程才执行。
  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <sys/types.h>
  4 #include <stdlib.h>
  5
  6 int main()
  7 {
  8     pid_t pid;
  9     int count = 0;
 10
 11     printf("parent id = %d\n", getpid());
 12
 13     pid = vfork();
 14     if (pid > 0)
 15     {
 16         while (1)
 17         {
 18             printf("this parent, pid = %d\n", getpid());
 19             printf("count = %d\n", count);
 20             sleep(1);
 21         }
 22     }
 23     if (pid == 0)
 24     {
 25         while (1)
 26         {
 27             printf("this child, pid = %d\n", getpid());
 28             sleep(1);
 29             count++;
 30             if (count == 4)
 31             {
 32                 exit(0);
 33             }
 34         }
 35     }
 36
 37     return 0;
 38 }

输出:

parent id = 17387
this child, pid = 17388
this child, pid = 17388
this child, pid = 17388
this child, pid = 17388
this parent, pid = 17387
count = 4
this parent, pid = 17387
count = 4
this parent, pid = 17387
count = 4

注:子进程非正常退出会影响变量状态

4. 进程终止

4.1 正常终止

  1. 在main函数内执行return语句
  2. 调用exit函数(标准c库)
  3. 调用_exit或_Exit函数(属于系统调用)
  4. 进程的最后一个线程在其启动例程中执行return语句,该线程的返回值不作用于进程的返回值。当最后一个线程从启动例程返回时,该进程以终止状态0返回。
  5. 最后一个线程调用pthread_exit函数。

4.2 异常终止

  1. 调用abort
  2. 当进程接收到某些信号时。
  3. 最后一个线程对取消(cancellation)请求做出响应

5. 等待子进程退出

僵尸进程:当子进程退出状态不被父进程收集会变成僵尸进程,kill对其无效。

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

pid_t wait(int *wstatus);

pid_t waitpid(pid_t pid, int *wstatus, int options);

5.1 wait

参数:(传出类型参数) 回收进程的状态。

返回值:

  • 成功: 回收进程的pid
  • 失败: -1, errno

函数作用:

  • 1: 阻塞等待子进程退出
  • 2: 清理子进程残留在内核的 pcb 资源
  • 3: 通过传出参数,得到子进程结束状态

获取子进程正常终止值:

  • WIFEXITED(status) 为真 调用 WEXITSTATUS(status) 得到 子进程 退出值。

获取导致子进程异常终止信号:

  • WIFSIGNALED(status)为真 调用 WTERMSIG(status) 得到 导致子进程异常终止的信号编号。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>

int main()
{
        pid_t pid;
        int count = 0;
        int status = 0;

        pid = vfork();
        if (pid > 0)
        {
                wait(&status);
                if (WIFEXITED(status))
                {
                        printf("child quit status = %d\n", WEXITSTATUS(status));
                }
                while (1)
                {
                        printf("this parent, pid = %d\n", getpid());
                        printf("count = %d\n", count);
                        sleep(1);
                }
        }
        if (pid == 0)
        {
                while (1)
                {
                        printf("this child, pid = %d\n", getpid());
                        sleep(1);
                        count++;
                        if (count == 2)
                        {
                                exit(3);
                        }
                }
        }

        return 0;
}

输出:

this child, pid = 17559
this child, pid = 17559
child quit status = 3
this parent, pid = 17558
count = 2
this parent, pid = 17558
count = 2

注:

  • 如果其所有子进程都还在运行,则阻塞。
  • 如果一个子进程已终止,正等待父进程获取其终止状态,则获得该子进程的终止状态立即返回。
  • 如果它没有任何子进程,则立即出错返回。

5.2 waitpid

参数:

  • pid:指定回收某一个子进程pid
    在这里插入图片描述
  • status:(传出) 回收进程的状态。
  • options:WNOHANG 指定回收方式为,非阻塞。
    在这里插入图片描述
    返回值:
  • 0 : 表成功回收的子进程 pid

  • 0 : 函数调用时, 参3 指定了WNOHANG, 并且,没有子进程结束。
  • -1: 失败。errno
    总结:
    wait、waitpid 一次调用,回收一个子进程
    使用while 回收多个进程

5.3 init进程

  • 它是内核启动的第一个用户级进程。init有许多很重要的任务,比如像启动getty(用于用户登录)、实现运行级别、以及处理孤立进程。
  • 父进程如果在子进程退出前退出,子进程就成为孤儿进程,Linux避免系统存在过多的孤儿进程,init进程会收留孤儿进程,成为其父进程。

6. exec族函数

https://blog.csdn.net/u014530704/article/details/73848573

7. system

 #include <stdlib.h>
 
 int system(const char *command);

函数原型:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
返回值:

  • 执行成功,返回进程的状态值
  • sh不能执行时,返回127
  • 失败返回-1
#include <stdio.h>
#include <stdlib.h>

int main()
{
        if (system("ps") == -1)
        {
                printf("system failed\n");
                perror("status:");
        }
        printf("system after");
        return 0;
}

输出:

    PID TTY          TIME CMD
  18895 pts/2    00:00:00 bash
  19001 pts/2    00:00:00 a.out
  19002 pts/2    00:00:00 sh
  19003 pts/2    00:00:00 ps

8. peopen

相比于system,可以获取运行的输出结果

#include <stdio.h>

FILE *popen(const char *command, const char *type);

int pclose(FILE *stream);

参数:

  • command: 是一个指向以 NULL 结束的 shell 命令字符串的指针。这行命令将被传到 bin/sh 并使用 -c 标志,shell 将执行这个命令。
  • mode: 只能是读或者写中的一种,得到的返回值(标准 I/O 流)也具有和 type 相应的只读或只写类型。如果 type 是 “r” 则文件指针连接到 command 的标准输出;如果 type 是 “w” 则文件指针连接到 command 的标准输入。
  • stream:popen返回的文件指针
    https://blog.csdn.net/libinbin_1014/article/details/51490568
    返回值:
  • 成功:则返回一个读或者打开文件的指针
  • 失败:返回NULL,具体错误根据errno判断
#include <stdio.h>
#include <stdlib.h>

int main()
{
        char buf[1024] = {0};
        FILE *fp = NULL;

        fp = popen("ps", "r");
        int n = fread(buf, 1, 1024, fp);
        printf("read %d byte, context: %s\n", n, buf);
        return 0;
}

输出:

read 151 byte, context:     PID TTY          TIME CMD
  18895 pts/2    00:00:00 bash
  19470 pts/2    00:00:00 a.out
  19471 pts/2    00:00:00 sh
  19472 pts/2    00:00:00 ps

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不知所云,

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值