长生栈 长生栈
首页
  • 编程语言

    • C语言
    • C++
    • Java
    • Python
  • 数据结构和算法

    • 全排列算法实现
    • 动态规划算法
  • CMake
  • gitlab 安装和配置
  • docker快速搭建wordpress
  • electron+react开发和部署
  • Electron-创建你的应用程序
  • ImgUI编译环境
  • 搭建图集网站
  • 使用PlantUml画时序图
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Living Team

编程技术分享
首页
  • 编程语言

    • C语言
    • C++
    • Java
    • Python
  • 数据结构和算法

    • 全排列算法实现
    • 动态规划算法
  • CMake
  • gitlab 安装和配置
  • docker快速搭建wordpress
  • electron+react开发和部署
  • Electron-创建你的应用程序
  • ImgUI编译环境
  • 搭建图集网站
  • 使用PlantUml画时序图
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 文件操作

  • Linux进程和线程

    • 进程创建
      • Linux进程模型
      • 进程标识
      • 取得进程号
      • fork系统调用
      • fork示例代码
      • 分析
    • 在进程中启动程序
    • 等待进程结束
    • 线程简介
    • 多线程编程举例
    • 线程同步
    • 线程属性
  • Linux信号

  • 进程间通信

  • Socket

  • C语言
  • Linux进程和线程
DC Wang
2023-02-17
目录

进程创建

# Linux进程创建

# Linux进程模型

进程是一个正在执行的程序的实例,由以下元素组成

  • 程序的当前上下文,程序当前的执行状态
  • 程序的当前执行目录
  • 程序访问的文件和目录
  • 程序的访问权限
  • 内存以及其他分配给进程的系统资源

# 进程标识

  • 进程最重要的属性是进程号(PID),以及父进程号(PPID)。一个进程有唯一的进程号,如果一个进程创建了一个子进程,那么它的进程号就是子进程的父进程号。

  • 1号进程( init ):负责引导系统、启动守护进程以及运行其他必要的程序。

# 取得进程号

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
    printf("PID = %d\n", getpid());     //取得当前进程的进程号
    printf("PPID = %d\n", getppid());   //取得父进程的进程号
    exit(EXIT_SUCCESS);
}
1
2
3
4
5
6
7
8
9

# fork系统调用

fork系统调用可以产生一个新进程。

#include<unistd.h>
pid_t fork( void );
1
2
  • 如果fork执行成功,就向父进程返回子进程的PID,并向子进程返回0。这意 味着即使只调用一次fork,也会返回两次!

  • fork创建的子进程是父进程的副本,二者的UID、GID、环境、资源、打开的文件、共享的内存段等完全相同。但是PID和PPID不同。

# fork示例代码

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    pid_t child;
    if((child = fork()) == -1) {
	perror("fork");
	exit(EXIT_FAILURE);
    } else if(child == 0) {
	puts("in child");
	printf("\tchild pid = %d\n", getpid());
	printf("\tchild ppid = %d\n", getppid());
	exit(EXIT_SUCCESS);
    } else {
	puts("in parent");
	printf("\tparent pid = %d\n", getpid());
	printf("\tparent ppid = %d\n", getppid());
    }
    exit(EXIT_SUCCESS);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

执行结果

in parent
in child
        parent pid = 2026
        child pid = 2027
        parent ppid = 1439
        child ppid = 2026
1
2
3
4
5
6

结果是乱序的,我们重新排列一下

in parent
        parent pid = 2026
        parent ppid = 1439
in child
        child pid = 2027
        child ppid = 2026
1
2
3
4
5
6

子进程的父进程号(ppid)是2026,正好是父进程的进程号(pid)。子进程在父进程之后生成,parent pid = 2026,child pid = 2027,child pid比parent pid多1,这也是符合期待的。

$ ps 1439
  PID TTY      STAT   TIME COMMAND
 1439 tty4     S      0:00 -bash
1
2
3

使用ps命令查看进程号1439对应的进程信息,对应的是bash。程序的父进程是bash。

上面乱序的结果是因为父、子进程和bash是完全异步的,没有确切的先后关系。

如果父进程在子进程前结束,子进程没有父进程了,子进程会把系统的守护进程(systemd)作为父进程。

# 分析

  • 程序执行结果表明,不能预计父进程是在子进程之前还是之后运行,程序的执行是无序的(异步的),因此,不应该在子进程中执行依赖于父进程的代码,反之亦然,因为二者异步执行。

  • 父进程由bash启动。

  • 父进程先执行结束,则子进程将系统守护进程systemd 作为自己的父进程。

编辑 (opens new window)
#C#Linux#进程
上次更新: 2023/02/18, 10:09:42
内存映射举例
在进程中启动程序

← 内存映射举例 在进程中启动程序→

最近更新
01
ESP32-网络摄像头方案
06-14
02
ESP32-PWM驱动SG90舵机
06-14
03
ESP32-实时操作系统freertos
06-14
更多文章>
Theme by Vdoing | Copyright © 2019-2025 DC Wang All right reserved | 辽公网安备 21021102001125号 | 吉ICP备20001966号-2
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式