C/C++进程超详细详解【上部分】(系统性学习day06)

简介: C/C++进程超详细详解【上部分】(系统性学习day06)

前言

进程和线程的广泛意义是什么?

进程是计算机中运行的程序的实例。它具有独立的内存空间和资源,是操作系统分配和管理资源的基本单位。每个进程都拥有独立的地址空间、全局变量和文件打开等资源,进程之间相互独立。进程之间通常通过进程间通信(IPC)机制进行数据交互。

线程是进程中的一个执行单元。一个进程可以包含多个线程,这些线程共享进程的地址空间和资源,可以同时执行不同的代码路径。线程之间可以通过共享内存进行数据交换,因为它们可以访问相同的全局变量和堆内存。


一、进程基础

1.进程概念

进程是一个独立的可调度的任务

   (1)进程是一个抽象实体。当系统在执行某个程序时,分配和释放的各种资源

   (2)进程是一个程序的一次执行的过程

进程和程序的区别

   程序是静态的,它是一些保存在磁盘上的指令的有序集合,没有任何执行的概念

   进程是一个动态的概念,它是程序执行的过程,包括创建、调度和消亡

   进程是程序执行和资源管理的最小单位

2.进程特征

动态性 ----程序一次运行过程

并发性 ----可以同时运行多个进程

独立性 ----每个进程在各自独立的虚拟内存中运行

异步性 ----多个运行的进程之间相互没有关系

3.进程状态(如图清晰可见)

4,进程的标识

(1)主要的进程标识

   进程号(Process Identity Number,PID)

   父进程号(Parent Process ID,PPID)

   

(2)PID唯一地标识一个进程。可以通过以下两个函数获得:

   pid_t getpid(void)     //获取进程ID

   pit_t getppid(void)    //获取父进程ID

实例代码如下:

int main(void)
    {
        printf("pid = %d\n",getpid());
        printf("ppid = %d\n",getppid());
        return 0;
    }

在终端运行的结果以及ps命令作用结果如下:

5.进程的种类

(1)交互进程:

   该类进程是由shell控制和运行的。交互进程既可以在前台运行,也可以在后台运行。

   

(2)批处理进程:

   该类进程不属于某个终端,它被提交到一个队列中以便顺序执行。

实例shell脚本程序如下:

       终端输入命令如下:

touch test.sh
        chmod a+x test.sh  
        test.sh内容如下:
        ls
        touch 1.txt 2.txt 3.txt
        ls /
        cat fork1.c

运行shell脚本文件如下:

peter@ubuntu:~/2308/proc/day01_code$ ./test.sh
     1.txt  3.txt   exit.c   fork2.c   main.c    myproc.c  test.sh  wait.c   waitpid.c
     2.txt  exec.c  fork1.c  getpid.c  Makefile  test.c    wait     waitpid
     bin   cdrom  etc   initrd.img      lib    lost+found  mnt  proc  run   snap  swapfile  tftpboot         u  sr  vmlinuz
     boot  dev    home  initrd.img.old  lib64  media       opt  root  sbin  srv   sys       tmp                 var    vmlinuz.old
     #include <stdio.h>
     #include <sys/types.h>
     #include <unistd.h>
     int main(void)
     {
         fork();
         printf("hello world\n");
         return 0;
      }

(3)守护进程:

         该类进程在后台运行。它一般在Linux启动时开始执行,系统关闭时才结束

二、进程API

1.创建子进程

pid_t fork(void);

fork调用过程:

   1,映射新的进程虚拟空间,该进程称为子进程。

   2,将父进程的各个数据段中的数据拷贝到子进程中

   3,父子进程共享代码段

   4,fork()调用过程返回两个值:

                 第一个值:给父进程返回子进程的ID号

                 第二个值:给子进程返回0

          调用失败返回:-1

   5,父子进程,从fork()调用的下一条语句同时运行  

实例代码如下:

void fun(void)
    {
        int i;
        for(i = 0 ; i  < 7; i++){
            printf("我是子进程,我要好好学习\n");
            sleep(1);
        }
    }
 
    int main(void)
    {
        int i;
        pid_t pid;
 
        if((pid = fork()) < 0){
            perror("fork");
            exit(1);
        }else if(!pid)
            fun();
        else
            for(i = 0 ; i  < 7; i++){
                printf("我是父进程,我要努力赚钱\n");
                sleep(1);
            }
        return 0;
    }

2.exec函数族

//加载另一个程序在进程的空间中执行
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, ... /* (char  *) NULL */);
int execlp(const char *file, const char *arg,.../* (char  *) NULL */);
int execle(const char *path, const char *arg,../*, (char *) NULL,char * const envp[] */);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);

函数族讲解图如下所示:

实例代码如下所示:

int main(void)
{
    int i;
    pid_t pid;
 
    if((pid = fork()) < 0){
        perror("fork");
        exit(1);
    }else if(!pid){   //子进程:执行另一个程序,如:ls
#if 0
        //execl("/bin/ls","ls","-l",NULL);
        //execlp("ls","ls","-l",NULL);
        char * arg[] = {"ls","-l",NULL};
        //execv("/bin/ls",arg);
        execvp("ls",arg);
#else
        //execl("/home/peter/2308/proc/day01_code/myproc","./myproc",NULL);
        char * env[] = {"name = peter","passwd = 123",NULL};
        //execle("/home/peter/2308/proc/day01_code/myproc","./myproc",NULL,env);
        char * arg[] = {"./myproc",NULL};
        execve("/home/peter/2308/proc/day01_code/myproc",arg,env);
#endif
    }else{   //父进程循环打印
        for(i = 0 ; ; i++){
            printf("我是父进程,我要努力赚钱\n");
            sleep(1);
        }
    }
    return 0;
}

3.结束进程

实例代码如下所示:

#include <stdlib.h>
void exit(int status);   //在结束进程之前,会先刷新缓冲,释放缓冲区,关闭打开的文件,然后再结束进程。
 
 #include <unistd.h>
 void _exit(int status);   //直接结束进程,不会刷新缓冲,释放缓冲区,关闭打开的文件
 //参数 ---status:  0-表示正常结束,非0-表示异常结束
 
 例如: 
 int main(void)
    {
        printf("hello world");
 
        //exit(1);     
        _exit(1);
 
        while(1);  
        return 0;     //在main函数中,执行return语句,return会调用exit()
    }

4.给进程收尸(释放进程占用的资源)

(1)wait

#include <sys/types.h>
    #include <sys/wait.h>
    //作用:给任意一个子进程收尸
     如果子进程没有结束,则父进程会阻塞,直到子进程结束为止。
     如果父进程没有子进程,则wait函数立即返回。               
    pid_t wait(int *wstatus);   
    //参数  ----- 保存子进程结束状态的变量地址
    //返回值 ----成功:收尸的子进程的ID,失败:-1

   

wait实例代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
 
 
int main(void)
{
    int i;
    pid_t pid1,pid2;
    int status;
 
    if((pid1 = fork()) < 0){
  perror("fork");
  exit(1);
    }else if(!pid1){
  for(i = 0 ; i  < 7; i++){
      printf("子进程1--pid = %d\n",getpid());
      sleep(1);
  }
  exit(0);
    }
    if((pid2 = fork()) < 0){
  perror("fork");
  exit(1);
    }else if(!pid2){
  for(i = 0 ; i  < 3; i++){
      printf("子进程2--pid = %d\n",getpid());
      sleep(1);
  }
  exit(120);
    }
    if(wait(&status) < 0){
  perror("wait");
  exit(1);
    }
    printf("给子进程收完尸\n");
    printf("status = %d\n",WEXITSTATUS(status));
    return 0;
}

(2)waitpid

//作用:给指定的进程收尸
    pid_t waitpid(pid_t pid, int *wstatus, int options);
    //参数1  ---pid:
                pid > 0   给进程号为pid的子进程收尸
                pid = -1  与wait()相同,给任意子进程收尸
                pid = 0   给与当前进程在同一个进程组的中任意子进程收尸
                pid < -1  给进程组ID为|pid|的进程组中任意子进程收尸
    //参数2 ----保存子进程结束状态的变量地址
    //参数3 ---- 选项,一般为0

waitpid实例代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
 
 
int main(void)
{
    int i;
    pid_t pid1,pid2;
    int status;
 
    if((pid1 = fork()) < 0){
  perror("fork");
  exit(1);
    }else if(!pid1){
  for(i = 0 ; i  < 7; i++){
      printf("子进程1--pid = %d\n",getpid());
      sleep(1);
  }
  exit(234);
    }
    if((pid2 = fork()) < 0){
  perror("fork");
  exit(1);
    }else if(!pid2){
  for(i = 0 ; i  < 3; i++){
      printf("子进程2--pid = %d\n",getpid());
      sleep(1);
  }
  exit(120);
    }
    if(waitpid(pid1,&status,0) < 0){
  perror("wait");
  exit(1);
    }
    printf("给子进程收完尸\n");
    printf("status = %d\n",WEXITSTATUS(status));
    return 0;
}


总结

     本篇文章针对进程线程进行超详细讲解,希望能够帮到大家!

      以后还会给大家展现更多关于嵌入式和C语言的其他重要的基础知识,感谢大家支持懒大王!

相关文章
|
3月前
麒麟系统mate-indicators进程占用内存过高问题解决
【10月更文挑战第7天】麒麟系统mate-indicators进程占用内存过高问题解决
413 2
|
11天前
|
监控 搜索推荐 开发工具
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
|
15天前
|
C++ 开发者
C++学习之继承
通过继承,C++可以实现代码重用、扩展类的功能并支持多态性。理解继承的类型、重写与重载、多重继承及其相关问题,对于掌握C++面向对象编程至关重要。希望本文能为您的C++学习和开发提供实用的指导。
48 16
|
1月前
|
算法 网络安全 区块链
2023/11/10学习记录-C/C++对称分组加密DES
本文介绍了对称分组加密的常见算法(如DES、3DES、AES和国密SM4)及其应用场景,包括文件和视频加密、比特币私钥加密、消息和配置项加密及SSL通信加密。文章还详细展示了如何使用异或实现一个简易的对称加密算法,并通过示例代码演示了DES算法在ECB和CBC模式下的加密和解密过程,以及如何封装DES实现CBC和ECB的PKCS7Padding分块填充。
56 4
2023/11/10学习记录-C/C++对称分组加密DES
|
1月前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
105 13
|
2月前
|
网络协议 Linux 虚拟化
如何在 Linux 系统中查看进程的详细信息?
如何在 Linux 系统中查看进程的详细信息?
277 1
|
2月前
|
Linux
如何在 Linux 系统中查看进程占用的内存?
如何在 Linux 系统中查看进程占用的内存?
|
3月前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
|
6月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
6月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
211 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)

热门文章

最新文章

相关实验场景

更多