linxu学习之进程

news2025/1/18 3:26:57

文章目录

  • 进程
    • 程序和进程
    • 产生进程
    • 销毁进程
    • 多进程高并发设计
    • 孤儿僵尸守护进程
      • 孤儿进程:
      • 守护进程(重点)
    • 僵尸进程:

进程

程序和进程

操作系统可以运行多个程序,那他是如何运行的?实际上,CPU的执行是很快的,而待运行的程序很多,那么为了让操作系统运行多个程序,CPU会把它的执行时间划分成很多段,比如每一段是0.1秒,那么就可以这样A程序运行0.1秒,然后B程序运行0.1,然后C程序运行0.2秒,因为这个切换很快,所以我们感觉程序是同时运行的。

产生进程

  • 创建进程很简单,直接调用fork函数:pid_t fork(void);

创建进程用法举例:

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

int main(){
    int pid = 0;// 父子进程不共享局部变量

    // pid_t fork(void);
    pid_t fpid = fork(); // fpid表示fork函数返回的值


    if(fpid < 0){
        printf("创建子进程失败\n");
        return fpid;
    }else if(fpid == 0){
    	// 创建成功后子进程中fpid == 0
        pid = getpid();
        printf("子进程,子进程pid = %d\n",getpid());
    }else if(fpid > 0){
    	// 创建成功后父进程的fpid 为子进程的pid
        pid = getpid();
        printf("父进程,父进程pid = %d\n",getpid());
        printf("父进程,子进程pid = %d\n",getpid());
    }
    
    // 再创建3个子进程用于观察
    for(int i = 3 ; i > 0 && fpid > 0 ; i--){
        fpid = fork();
    }
    printf("pid = %d\n",pid);

    while (1);
    return 0;
}

在这里插入图片描述

调用fork函数后,会创建一个子进程,并且父子两个进程都从fork处执行,fork函数有两个返回值,对于父进程会返回子进程的pid,此时pid会大于0,对于子进程来说,pid会等于0。

局部变量:写时复制,读时共享

销毁进程

exit - 终止正在执行的进程

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

int main()
{
    int pid = 0;

    // pid_t fork(void);
    pid_t fpid = fork();

    if (fpid < 0)
    {
        printf("创建子进程失败\n");
        return fpid;
    }
    else if (fpid == 0)
    {
        printf("我是子进程,马上就要exit了\n");
        exit(-1);
        printf("子进程还活着\n");
    }
    else if (fpid > 0)
    {
        printf("父进程还活着\n");
    }

    while (1);

    return 0;
}

这里子进程已经退出,但是父进程没有执行完毕,导致子进程没有回收变成僵尸进程
在这里插入图片描述

多进程高并发设计

在这里插入图片描述
优点:

  • 若要用多进程实现高并发那么自己linxu系统cpu有多少核,就产生多少个进程多个核可以并发执行只有多个进程在不同的核上运行才可以充分利用多核系统的并发处理能力

  • 比如:cpu为四核,那么主进程就产生4个子进程,让四个子进程分别在不同的核上运行,

  • 4个子进程在工作的时候,把任务放在一个共享内存中(通过内存映射,使多个进程可以访问一个内存),哪个任务做完了,就接着拿任务给每个子进程的负载均衡

  • 职责明确:父进程管理生死,子进程工作

查看cpu核数

cat /proc/cpuinfo
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>

typedef void (*spawn_proc_pt)(void *data);
static void worker_process_cycle(void *data);
static void start_worker_processes(int n);
pid_t spawn_process(spawn_proc_pt proc, void *data, char *name);

int main(int argc, char **argv)
{
    // 子进程用于工作,父进程用于管理子进程

    // 开启工作进程,创建4个子进程
    start_worker_processes(4);
    // 管理子进程
    wait(NULL);
}

// 开启工作进程
void start_worker_processes(int n)
{
    int i = 0;
    for (i = n - 1; i >= 0; i--)
    {
        // 创建子进程
        spawn_process(worker_process_cycle, (void *)(intptr_t)i, "worker process");
    }
}

// 创建子进程
// spawn_proc_pt 类型的函数:void worker_process_cycle(void *data)
pid_t spawn_process(spawn_proc_pt proc, void *data, char *name)
{
    pid_t pid;
    pid = fork(); // 创建子进程

    switch (pid)
    {
    case -1:
        fprintf(stderr, "fork() failed while spawning \"%s\"\n", name);
        return -1;
    case 0:
        proc(data); // 成功创建子进程后让子进程去工作
        return 0;
    default:
        break;
    }
    printf("start %s %ld\n", name, (long int)pid);
    return pid;
}

// 给进程安排工作
void worker_process_cycle(void *data)
{
    // data 其实是一个int*类型
    int worker = (intptr_t)data;
    // 初始化
    worker_process_init(worker);

    // 干活
    for (;;)
    {
        sleep(10);
        printf("pid %ld ,doing ...\n", (long int)getpid());
    }
}

// 初始化进程
void worker_process_init(int worker)
{
    cpu_set_t cpu_affinity;
    // worker = 2;
    // 多核高并发处理  4core  0 - 0 core 1 - 1  2 -2 3 -3
    CPU_ZERO(&cpu_affinity); // 结构体清零
    
    // CPU_SETSIZE:1024 支持cpu最大的数量
    CPU_SET(worker % CPU_SETSIZE, &cpu_affinity); // 0 1 2 3 设置核

    /*
    在多CPU系统中,通过sched_setaffinity ()可以设置进程的CPU亲和力,
    使进程绑定在某一个或几个CPU上运行,避免在CPU之间来回切换,从而提高该进程的实时性能。
    */
    if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_affinity) == -1)
    {
        fprintf(stderr, "sched_setaffinity() failed\n");
    }
}

查看进程对应的核数
在这里插入图片描述

代码中函数指针不太理解的看看下方代码:

// typedef  返回类型(*新类型)(参数表)
typedef char (*PTRFUN)(int); 
PTRFUN pFun; 
char glFun(int a){ return;} 
void main() 
{ 
    pFun = glFun; 
    (*pFun)(2);  //调用函数
} 

查看进程在cpu的核上执行的命令: ps -eLo ruser,pid,lwp,psr,args

孤儿僵尸守护进程

孤儿进程:

一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程所收养,并由init进程对它们完成状态收集工作。
想想我们如何模仿一个孤儿进程? 答案是: kill 父进程!

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

int main(){
    int fpid = 1;// 父子进程不共享局部变量

    for(int i = 5 ; i > 0 && fpid > 0 ; i--){
        fpid = fork();
    }

    if(fpid < 0){
        printf("创建子进程失败\n");
        return fpid;
    }else if(fpid == 0){
    	while(1);
    }else if(fpid > 0){
        while(1);
    }

    return 0;
}

在这里插入图片描述

守护进程(重点)

把孤儿进程做成守护进程

不与任何终端关联的进程,通常情况下守护进程在系统启动时就在运行,它们以root用户或者其他特殊用户(apache和postfix)运行,并能处理一些系统级的任务。守护进程脱离于终端,是为了避免进程在执行过程中的信息在任何终端上显示,并且进程也不会被任何终端所产生的终端信息所打断(比如关闭终端等)。那如何成为一个守护进程呢? 步骤如下:

  • 1.调用fork(),创建新进程,它会是将来的守护进程.
  • 2.在父进程中调用exit(父进程挂掉),保证子进程不是进程组长
  • 3.调用setsid()创建新的会话区 – 具体先不追究
  • 4.将当前目录改成根目录(如果把当前目录作为守护进程的目录,当前目录不能被卸载他作为守护进程的工作目录)
  • 5.将标准输入,标准输出,标准错误重定向到/dev/null.
    我们来看这个代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

// 一般传入 0 , 0
int daemon(int nochdir, int noclose)
{
    int fd = 0;
    switch (fork())
    {
    case -1:
        return (-1);
    case 0:
        break;
    default:
        _exit(0); // 父进程自杀
    }

    if (setsid() == -1) // 创建会画
        return (-1);
    
    if (!nochdir) // 将当前目录改成根目录
        (void)chdir("/");

    if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1)
    {
        // 重定向 标准输入 标准输出 标准出错
        (void)dup2(fd, STDIN_FILENO);
        (void)dup2(fd, STDOUT_FILENO);
        (void)dup2(fd, STDERR_FILENO);
        if (fd > 2)
            (void)close(fd);
    }

    return (0);
}


int main()
{
    // 创建子进程,并且把父进程杀死
    daemon(0,0);

    printf("hello\n");

    while(1);// 处理事务
    

    return 0;
}

父进程自杀后,守护进程 init 接管 , 一直在后台进行运行
在这里插入图片描述

僵尸进程:

一个进程使用fork创建子进程,如果子进程退出(exit),而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

  1. 僵尸进程怎样产生的:
  • 一个进程使用fork创建子进程,如果子进程退出(exit),而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
  • 它需要它的父进程来为它收尸,如果他的父进程没安装 SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了, 那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。

1.怎么查看僵尸进程:
  利用命令ps,可以看到有标记为的进程就是僵尸进程。

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

int main(){
    pid_t fpid = fork();


    if(fpid < 0){
        printf("创建子进程失败\n");
        return fpid;
    }else if(fpid == 0){
        exit(-1);
    }else if(fpid > 0){
       while(1);
    }

     
    return 0;
}

这里可以用 wait 和 waitpid 函数回收子进程
在这里插入图片描述
2.怎样来清除僵尸进程:

  • 改写父进程,在子进程死后要为它收尸。具体做法是接管SIGCHLD信号。子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。这是基于这样的原理:就算父进程没有调用 wait,内核也会向它发送SIGCHLD消息,尽管对默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。
  • 把父进程杀掉。父进程死后,僵尸进程成为"孤儿进程",过继给1号进程init,init始终会负责清理僵尸进程。它产生的所有僵尸进程也跟着消失。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/415270.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《随便测测》WEB接口测试平台

编写用例的船新版本&#xff0c;从未有过的顺滑体验背景在保证用例运行稳定、高效、准确的前提下以降低测试人员编写用例的时间为目的&#xff0c;减少编写用例的复杂度&#xff0c;达到提升效率的目的。解决问题因被测系统业务流程长&#xff0c;接口多&#xff08;多的一个场…

【ssl认证、证书】SSL 证书基本概念、证书格式、openssl和keytool的区别

文章目录1. keytool VS openssl2. X.509 VS PKCS2.1 PKCS2.2 X.5092.2.1 证书编码格式2.2.1.1 DER 证书编码格式二进制2.2.1.2 文本格式 pem2.2.2 文件后缀名3. 常见Web服务软件及证书格式参考相关文章&#xff1a;//-----------Java SSL begin----------------------【ssl认证…

【云原生】k8s集群命令行工具kubectl之集群管理命令

kubectl集群管理命令详解一、准备工作1.1、Replication Controller1.2、Deployment1.3、DaemonSet1.4、查看创建的svc和pod1.5、kubectl 命令自动补全设置二、集群管理命令2.1、top2.2、cordon2.3、uncordon2.4、drain2.5、taint2.5.1、污点设置。2.5.2、容忍度使用一、准备工作…

Scala之函数式编程

目录 函数和方法的区别&#xff1a; 参数默认值&#xff1a; 函数至简原则---能省则省&#xff1a; 至简原则细节 匿名函数的化简&#xff1a; 匿名函数至简原则&#xff1a; 高阶函数&#xff1a; 高阶函数的三种用法&#xff1a; &#xff08;1&#xff09;函数可以作…

【K8S系列】深入解析Pod对象(二)

目录 序言 1.Volume 简单介绍 2 Projected Volume 介绍 2.1 Secret 2.1.1 yaml讲解 2.1.2 创建Pod 2.2 Downward API 2.2.1 yaml示例 2.2.2 Downward API 支持字段 3 投票 序言 任何一件事情&#xff0c;只要坚持六个月以上&#xff0c;你都可以看到质的飞跃。 在…

SqlServer实用系统视图,你了解多少?

SqlServer实用系统视图&#xff0c;你了解多少&#xff1f;前言master..spt_valuessysdatabasessysprocesses一套组合拳sysobjectssys.all_objectssyscolumnssystypessyscommentssysindexes结束语前言 在使用任何数据库软件的时候&#xff0c;该软件都会提供一些可能不是那么公…

小规模容器编排使用Docker Swarm不香么,用个锤子的kubernetes

文章目录一、Docker Swarm是什么&#xff1f;二、Swarmkit和Swarm Mode是什么&#xff1f;三、Docker Swarm的核心设计四、Docker Swarm安装部署4.1、初始化Swarm节点14.2、新节点加入Swarm集群4.3、使用swarm部署服务4.4、swarm集群管理一、Docker Swarm是什么&#xff1f; D…

“QT 快速上手指南“ 之 计算器(二)组件,坐标,窗口

文章目录前言一、QT 基本组件用法介绍&#xff1a;1. QLabel &#xff1a;2. QPushButton :3. QLineEdit:二、坐标系统三、窗口部件的大小设置1. setSize( ) 函数&#xff1a;2. resize( )函数&#xff1a;3. setFixedSize( )函数:4. setFixedWidth( ) 和 setFixedHeight( )函数…

标准化归一化方法

一、经典机器学习的归一化算法 分别是0-1标准化&#xff08;Max-Min Normalization&#xff09;和Z-Score标准化。 1.1 0-1标准化方法 每一列中的元素减去当前列的最小值&#xff0c;再除以该列的极差。 不过在深度学习领域&#xff0c;我们更希望输入模型的数据是Zero-Ce…

使用Serv-U搭建FTP服务器并公网访问【内网穿透】

文章目录1. 前言2. 本地FTP搭建2.1 Serv-U下载和安装2.2 Serv-U共享网页测试2.3 Cpolar下载和安装3. 本地FTP发布3.1 Cpolar云端设置3.2 Cpolar本地设置4. 公网访问测试5. 结语1. 前言 科技日益发展的今天&#xff0c;移动电子设备似乎成了我们生活的主角&#xff0c;智能手机…

这些IT行业趋势,将改变2023

上一周&#xff0c;你被"AI"刷屏了吗&#xff1f; 打开任何一家科技媒体&#xff0c;人工智能都是不变的热门话题。周初大家还在用ChatGPT写论文、查资料、写代码&#xff0c;到周末的时候大家已经开始用GPT-4图像识别来做饭、Microsoft 365 Copilot 来写PPT了。 GP…

【周末闲谈】AI的旅途

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️周末闲谈】 系列目录 ✨第一周 二进制VS三进制 ✨第二周 文心一言&#xff0c;模仿还是超越&#xff1f; ✨第二周 畅想AR 文章目录系列目录前言AIAI的开端第一个AI程序AI的寒冬关于AI的思考末尾前言…

憨批的语义分割重制版11——Keras 搭建自己的HRNetV2语义分割平台

憨批的语义分割重制版11——Keras 搭建自己的HRNetV2语义分割平台学习前言什么是HRNetV2模型代码下载HRNetV2实现思路一、预测部分1、主干网络介绍a、Section-1b、Section-2c、Section-3d、Section-42、特征整合部分3、利用特征获得预测结果二、训练部分1、训练文件详解2、LOSS…

【Python童年游戏】满满的回忆杀—那些年玩过的童年游戏你还记得吗?那个才是你的菜?看到第一个我就泪奔了(致我们逝去的青春)

导语 滴一一学生卡&#x1f64c; 结伴上车的学生仔子们 用笑声打破车厢的沉默 大人眼里的晚高峰 是给放学后快乐&#x1f600;时光的加时 下车的学生匆匆起身带起 一阵熟悉的栀子香于&#x1f493; 是关于校园的记忆 开始零零散散地闪现 放学后集合的秘密基地/跟着城…

Half-UNet:用于医学图像分割的简化U-Net架构

Half-UNet简化了编码器和解码器&#xff0c;还使用了Ghost模块(GhostNet)。并重新设计的体系结构&#xff0c;把通道数进行统一。 论文动机 编码器的不同类型的架构图&#xff0c;编码器(A-C)的结构分别来源于U-Net的编码器、解码器和全的Unet结构。 下面是上图的一些结果指标…

4.2学习周报

文章目录前言文献阅读摘要介绍时间序列预测目前存在的问题时间序列预测方法分类未来方向时间序列预测总结前言 本周阅读文献《Forecast Methods for Time Series Data: A Survey》&#xff0c;本文主要对目前时间序列数据建模方法进行分类&#xff0c;主要分为了三类&#xff…

Linux->文件系统磁盘文件管理

目录 1 磁盘结构 2 逻辑抽象管理磁盘 2.1 逻辑抽象 2.2 管理磁盘 2.3 补充知识 3 软硬连接 1 磁盘结构 本篇的学习需要建立在大家在脑海中有一副磁盘的结构才能进行下去&#xff0c;所以我会以图解的方式为大家简单讲解一下&#xff0c;注&#xff1a;博主对这一部分并不是…

深度学习实战——卷积神经网络/CNN实践(LeNet、Resnet)

忆如完整项目/代码详见github&#xff1a;https://github.com/yiru1225&#xff08;转载标明出处 勿白嫖 star for projects thanks&#xff09; 系列文章目录 本系列博客重点在深度学习相关实践&#xff08;有问题欢迎在评论区讨论指出&#xff0c;或直接私信联系我&#xf…

详细介绍别人电脑访问到自己电脑运行的项目

文章目录 让别人远程访问你的代码网站项目或临时演示你的项目给客户的方式详解 引言一、创建一个你想要别人访问的项目二、明确你想要将这个网站或者项目存放的地方 终端分类服务器设备WEB服务器三、部署我们的网页 本地部署流程进入浏览器输入网址访问获取本机的IP地址&#…

多模态特征融合:图像、语音、文本如何转为特征向量并进行分类

多模态特征融合前言输入层&#xff0c;数据集转为特征向量图像语音什么是时域信号&#xff0c;什么是频域信号语音信号转换 - 1.傅立叶变换语音信号转换 - 2.梅尔频率倒谱系数文本词袋模型词嵌入模型输出层&#xff0c;多模态模型合并前言 学习多模态的话题可以从深度学习的分…