Linux高级系统编程-3 进程
概念
进程与程序的区别
单道程序和多道程序
并行和并发
进程块控制(PCB)
进程号
概念:
每个进程都由一个进程号来标识,其类型为 pid_t(整型),进程号的范围:0~ 32767。进程号总是唯一的,但进程号可以重用。当一个进程终止后,其进程号就可以 再次使用
获取进程id
获取进程的父进程id
获取进程所在进程组id
创建进程fork()
概述
父子进程,系统允许一个进程可以创建新进程,该进程即为新进程的父进程,新进程即为子进程
函数
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char const *argv[])
{printf("啦啦啦\n");
/**
* fork():创建一个进程
* 参数:无
* 返回值:
* 父进程中返回子进程的id
* 子进程中返回0
* -1表示创建失败
* 注意:子进程执行是从fork后开始执行
*/int id = fork();if (id < 0){printf("创建失败id:%d\n",id);}else if(id > 0){printf("父进程id:%d\n,创建的子进程id:%d\n",getpid(),id);}else if (id == 0){printf("父进程id:%d\n,创建的子进程id:%d\n,创建的id:%d\n",getppid(),getpid(),id);}printf("德玛西亚\n");while(1);return 0;
} 父子进程关系
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char const *argv[])
{printf("啦啦啦\n");int id = fork();printf("德玛西亚\n");while(1);return 0;
} 结果:
啦啦啦
德玛西亚
德玛西亚
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char const *argv[])
{printf("啦啦啦");int id = fork();printf("德玛西亚\n");while(1);return 0;
} 结果:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main(int argc, char *argv[])
{//printf是库函数有缓冲区 hello world先放入缓冲区 被子进程复制了一份printf("hello world1");//write是系统调用 直接将字符串 写入1号文件 没有缓冲区 不被子进程复制//0,输入//1,输出//2,错误输出write(1,"hello world2",12);//创建子进程pid_t pid = fork();return 0;
} 结果:hello world1hello world2hello world1
进程状态
ps查看进程状态
进程资源的回收
wait函数
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{int pid = fork();if(pid < 0){printf("创建进程失败");}else if(pid == 0){for(int i = 0; i < 10; i++){printf("子进程%u正在执行第%d次\n",getpid(),i);/*sleep:休眠参数休眠时间liunx下参数单位秒,windows下单位毫秒*/sleep(1);}}else if(pid > 0){printf("父进程正在等待子进程执行完毕\n");wait(NULL);printf("父进程已经回收了子进程%u\n",pid);}return 0;
} exit函数与_exit函数
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{int pid = fork();if(pid < 0){printf("创建进程失败");}else if(pid == 0){for(int i = 0; i < 10; i++){printf("子进程%u正在执行第%d次\n",getpid(),i);/*sleep:休眠参数休眠时间liunx下参数单位秒,windows下单位毫秒*/sleep(1);}//进程退出//参数0正常退出,非0异常退出,参数就是子进程退出状态值//exit(-1);//库函数,底层封装_exit,效率低_exit(-1);//系统调用函数,效率高printf("Hello");//因为子进程已经退出,所以此代码不会执行}else if(pid > 0){printf("父进程正在等待子进程执行完毕\n");wait(NULL);printf("父进程已经回收了子进程%u\n",pid);}return 0;
} WIFEXITED(status)与WEXITSTATUS(status)
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{int pid = fork();if(pid < 0){printf("创建进程失败");}else if(pid == 0){for(int i = 0; i < 3; i++){printf("子进程%u正在执行第%d次\n",getpid(),i);/*sleep:休眠参数休眠时间liunx下参数单位秒,windows下单位毫秒*/sleep(1);}//进程退出//参数就是子进程退出状态值//exit(100);//库函数,底层封装_exit,效率低_exit(100);//系统调用函数,效率高printf("Hello");//因为子进程已经退出,所以此代码不会执行}else if(pid > 0){printf("父进程正在等待子进程执行完毕\n");int status = 0;pid_t ret = wait(&status);printf("子进程%u,是否正常退出(WIFEXITED):%d\t,退出状态值(WEXITSTATUS)为:%d\n",ret,WIFEXITED(status),WEXITSTATUS(status));printf("父进程已经回收了子进程%u\n",pid);}return 0;
} waitpid函数
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>//exit
int main(int argc, char *argv[])
{//创建子进程pid_t pid = fork();if(pid < 0){perror("fork\n");}else if(pid == 0)//子进程{int i=0;for(i=10;i>0;i--){printf("子进程%u剩余的生命%d\n", getpid(), i);sleep(1);}//进程退出//exit(-1);//库函数 底层调用的系统调用_exit_exit(10);//系统调用函数 10就是子进程退出的状态值}else if(pid > 0)//父进程{int status = 0;printf("父进程%u 等待子进程%u的结束\n",getpid(),pid );pid_t ret = waitpid(-1, &status, 0);//不关心状态 直接实参为NULLif(WIFEXITED(status))//子进程正常退出{//取出状态值printf("子进程%u已经结束 状态值为:%d\n", ret,WEXITSTATUS(status));}}return 0;
} atexit 函数
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
void fun()
{printf("进程退出\n");
}
int main(int argc, char const *argv[])
{//atexit()int p_id = fork();if(p_id == 0){atexit(fun);//子进程printf("子进程已开启\n");sleep(1);printf("子进程退出\n");exit(10);}else if(p_id > 0){//主进程wait(NULL);sleep(5);printf("父进程结束\n");}return 0;
} #include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
void fun01()
{printf("函数1\n");
}
void fun02()
{printf("函数2\n");
}
void fun03()
{printf("函数3\n");
}
int main(int argc, char const *argv[])
{atexit(fun01);atexit(fun02);atexit(fun03);atexit(fun01);sleep(3);return 0;
} 特殊进程
僵尸进程
孤儿进程
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>//exit
int main(int argc, char *argv[])
{//创建子进程pid_t pid = fork();if(pid < 0){perror("fork\n");}else if(pid == 0)//子进程{printf("子进程%u\n", getpid());while(1);_exit(-1);}else if(pid > 0)//父进程{}return 0;
} 守护进程
创建守护进程步骤
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char const *argv[])
{// 1,忽略挂断信号SIGHUP,防止被终端误杀//SIG_IGN:忽略指定的信号signal(SIGHUP, SIG_IGN);pid_t pid = fork();//父进程结束if (pid > 0)_exit(-1);//子进程设置会话setsid();//改变工作目录(非必须)chdir("/");//设置权限掩码umask(0002);//关闭文件描述符0 1 2close(0);close(1);close(2);//守护进程的核心任务while (1){//核心任务}return 0;
} 多进程
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{//错误演示:创建两个子进程//实际创建了3个,主线程2个,子线程一个// for (int i = 0; i < 2; i++)// {// int pid = fork();// }//正确演示:创建两个子进程//主线程创建2个,子线程不创建for (int i = 0; i < 2; i++){int pid = fork();if(pid == 0){break;}}return 0;
} 退出
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>//exit
int main(int argc, char *argv[])
{//创建3个子进程int i=0;for(i=0;i<3;i++){pid_t pid = fork();if(pid == 0)//子进程break;}if(i==0)//子进程1{//任务1的代码printf("子进程1:%u\n", getpid());sleep(5);_exit(-1);}else if(i==1)//子进程2{//任务2的代码printf("子进程2:%u\n", getpid());sleep(3);_exit(-1);}else if(i==2)//子进程3{//任务3的代码printf("子进程3:%u\n", getpid());sleep(4);_exit(-1);}else if(i == 3)//父进程{//回收子进程的资源while(1){//-1:等待任一子进程//WNOHANG:不阻塞pid_t ret = waitpid(-1, NULL, WNOHANG);if(ret > 0){printf("子进程:%u已经退出\n", ret);}else if(ret == 0){continue;//还有子进程在运行 需要继续等待}else if(ret < 0){break;//所有子进程都已经结束}}}return 0;
} 进程补充
终端
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>//exit
int main(int argc, char *argv[])
{pid_t pid = fork();if(pid == 0)//子进程{sleep(3);int num = 0;scanf("%d", &num);printf("子进程%u中的num=%d,所属终端名:%s\n", getpid(), num,ttyname(0));}else if(pid > 0)//父进程{int num = 0;scanf("%d", &num);printf("父进程%u中的num=%d,所属终端名:%s\n", getpid(), num,ttyname(0));}return 0;
} 进程组
获取所属进程组id
设置进程组
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>//exit
int main(int argc, char *argv[])
{pid_t pid = fork();setpgid(pid,pid);if(pid == 0)//子进程{printf("子进程%d,所属组id:%d\n", getpid(), getpgrp());}else if(pid > 0)//父进程{printf("父进程%d,所属组id:%d\n", getpid(), getpgrp());}while(1);return 0;
} 会话
函数getsid
函数setid
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>//exit
int main(int argc, char *argv[])
{pid_t pid = fork();if(pid == 0)//子进程{printf("子进程1id:%d\t,所属组id:%d\t,会话id:%d\n",getpid(),getpgrp(),getsid(getpid()));sleep(2);setsid();printf("子进程2id:%d\t,所属组id:%d\t,会话id:%d\n",getpid(),getpgrp(),getsid(getpid()));while(1);}else if(pid > 0)//父进程{printf("主进程id:%d\t,所属组id:%d\t,会话id:%d\n",getpid(),getpgrp(),getsid(getpid()));while(1);}return 0;
} vfork函数
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{int num = 10;// pid_t pid = fork();pid_t pid = vfork();if(pid == 0)//子进程{num=100;printf("子进程num=%d\n",num);// sleep(3);_exit(-1);}else if(pid > 0)//父进程{// wait(NULL);printf("主进程num=%d\n",num);}return 0;
} exec函数族
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{//which 命令,查看命令存储路径/*execl("命令存储路径","命令名","参数1","参数2",...,NULL);*/// execl("/usr/games/sl","sl",NULL);// execl("/bin/ls","ls","-a","-l","-h",NULL);// execl("/bin/ls","ls","-alh",NULL);/*execlp:从path环境变量下查找指定名,如果没有无法运行execlp("命令名","命令名","参数1","参数2",...,NULL)env命令查看环境变量*/// execlp("ls","ls","-alh",NULL);// char *tem[] = {"/ls","-alh",NULL};// execv("/bin/ls",tem);char *tem[] = {"/ls","-alh",NULL};//execvp("ls",tem);execvpe("ls",tem);return 0;
} exec函数和当前进程的关系
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{printf("exec执行前\n");//exec后的程序将不在执行execl("/bin/ls","ls","-alh",NULL);printf("exec执行后\n");return 0;
} exec函数vfork的关系
#45_test.c文件
#include <stdio.h>
#include <unistd.h>q
int main(int argc, char const *argv[])
{for (int i = 0; i < 3; i++){printf("test:%d\n",i);sleep(1);}return 0;}
#使用gcc 45_test.c -o 45_test,将源文件编译为可执行文件
#45_code.c文件
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{int pid = vfork();if (pid < 0){printf("创建进程失败");return 0;}else if(pid == 0){//子进程中代码// for(int i = 0; i < 3; i++)// {// sleep(1);// printf("子进程:%d\n",i);// }execl("./45_test","45_test",NULL);_exit(-1);}else if(pid > 0){// 父进程中代码for(int i = 0; i < 6; i++){printf("code:%d\n",i);sleep(1);}return 0;
} system函数
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{printf("system前\n");system("ls -alh");printf("system后\n");return 0;
} 相关文章:
Linux高级系统编程-3 进程
概念 进程与程序的区别 程序:一个可执行文件, 占磁盘空间,是静态的 进程:一个程序运行的过程, 占内存,动态的。 单道程序和多道程序 单道程序设计: 所有进程一个一个排队执行。若 A 阻塞, B 只能等待࿰…...
ES-ELSER 如何在内网中离线导入ES官方的稀疏向量模型(国内网络环境下操作方法)
ES官方训练了稀疏向量模型,用来支持语义检索。(目前该模型只支持英文) 最好是以离线的方式安装。在线的方式,在国内下载也麻烦,下载速度也慢。还不如用离线的方式。对于一般的生产环境,基本上也是网络隔离的…...
Excel 使用技巧
Excel 使用技巧 注意: excel 中设计计算的字符尽量使用英文。 拼接两段文字(字符串拼接) 方法一 在需要计算的单元格上,键入 点击 A1(点击需要拼接的单元格) & C1(点击需要拼接的单元格) 举例: 姓名栏想要拼接 姓 和 名 两列点击姓名这一…...
Hadoop学习笔记(HDP)-Part.03 资源规划
目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …...
一个最新国内可用的免费GPT4,Midjourney绘画网站+使用教程
一、前言 ChatGPT GPT4.0,Midjourney绘画,相信对大家应该不感到陌生吧?简单来说,GPT-4技术比之前的GPT-3.5相对来说更加智能,会根据用户的要求生成多种内容甚至也可以和用户进行创作交流。 然而,GPT-4对普…...
深入了解Java8新特性-日期时间API之ZonedDateTime类
阅读建议 嗨,伙计!刷到这篇文章咱们就是有缘人,在阅读这篇文章前我有一些建议: 本篇文章大概19000多字,预计阅读时间长需要10分钟以上。本篇文章的实战性、理论性较强,是一篇质量分数较高的技术干货文章&…...
使用Vue写一个日期选择器
在 Vue 中实现日期选择器的方法有很多,下面提供一个简单的实现方法。 首先,在需要使用日期选择器的组件中引用 Vue 和 date-fns 库,date-fns 库是一个轻量级的 JavaScript 时间日期工具库,可以方便地处理日期的格式化和计算。 &…...
19、pytest通过mark标记测试函数
官方实例 [pytest] markers slow:marks tests as slow(deselect with -m "not slow")serial# content of test_mark.py import pytestpytest.mark.slow def test_mark_function():print("test_mark_function was invoked")assert 0解读与实操 通过使用p…...
Linux环境变量与命令行参数
Linux环境变量与命令行参数 一.命令行参数1.语法2.应用1:简易计算器 二.环境变量1.环境变量的概念2.环境变量的作用3.进一步理解环境变量的作用4.常见环境变量5.导出环境变量(添加环境变量)6.环境变量的特性7.另一种获取环境变量的方式8.小功能:用于身份验证的代码9.补充:第三种…...
jQuery实现3D轮播图
通过CSS3的3D变换和jQuery Transit插件实现了一个3D旋转的图片轮播效果 HTML部分: div id“banner”:定义了一个id为"banner"的div标签,作为图片轮播的容器。 ul: 在"banner"中定义了一个无序列表,每个列表项…...
Java面试题(每天10题)-------连载(43)
目录 Spring篇 1、请举例说明Qualifier注解 2、构造方法注入和设值注入有什么区别? 3、Spring框架中有哪些不同类型的事件? 4、FileSystemResource和ClassPathResource有什么区别? 5、Spring框架中都用到了哪些设计模式? 6…...
Python高级数据结构——并查集(Disjoint Set)
Python中的并查集(Disjoint Set):高级数据结构解析 并查集是一种用于处理集合的数据结构,它主要支持两种操作:合并两个集合和查找一个元素所属的集合。在本文中,我们将深入讲解Python中的并查集࿰…...
pytorch学习9-优化器学习
系列文章目录 pytorch学习1-数据加载以及Tensorboard可视化工具pytorch学习2-Transforms主要方法使用pytorch学习3-torchvisin和Dataloader的使用pytorch学习4-简易卷积实现pytorch学习5-最大池化层的使用pytorch学习6-非线性变换(ReLU和sigmoid)pytorc…...
MySQL之锁
MySQL之锁 锁是计算机在执行多线程或线程时用于并发访问同一共享资源时的同步机制,MySQL中的锁是在服务器层或者存储引擎层实现的,保证了数据访问的一致性与有效性 MySQL锁可以按模式分类为:乐观锁与悲观锁。 按粒度分可以分为全局锁、表级锁…...
今日现货黄金最新建议
近期现货黄金价格再度逼近历史高位,很多本来在场外观望的投资者,都纷纷希望进场一试身手。然而大涨大跌的行情并不是很适合新手投资者参与,如果大家还没做好技术上的准备,可以多听听正规交易平台的专业人士的意见。 在正式入市之前…...
基于混沌算法的图像加密解密系统
1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义: 随着信息技术的迅猛发展,图像的传输和存储已经成为现代社会中不可或缺的一部分。然而,随着互联网的普及和信息的快速传播&am…...
vscode插件离线下载
离线下载插件地址:https://marketplace.visualstudio.com/VSCode...
第二十一章总结
一、网络通信: 1.网络程序设计基础:网络程序设计编写的是与其他计算机进行通信的程序。 1.1局域网与互联网:为了实现两台计算机的通信,必须用一个网络线路连接两台计算机 2.网络协议:网络协议规定了计算机之间连接的…...
查看端口占用并杀死进程
1.安装查看工具 sudo yum install net-tools 2.查看占用情况 netstat -tunlp | grep 8089 3.杀死进程 kill -9 227...
前后端数据传输格式(上)
作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 作为后端,写…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...
STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...
rm视觉学习1-自瞄部分
首先先感谢中南大学的开源,提供了很全面的思路,减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接:https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架: 代码框架结构:readme有…...
大模型——基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程
基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程 下载安装Docker Docker官网:https://www.docker.com/ 自定义Docker安装路径 Docker默认安装在C盘,大小大概2.9G,做这行最忌讳的就是安装软件全装C盘,所以我调整了下安装路径。 新建安装目录:E:\MyS…...
深入解析 ReentrantLock:原理、公平锁与非公平锁的较量
ReentrantLock 是 Java 中 java.util.concurrent.locks 包下的一个重要类,用于实现线程同步,支持可重入性,并且可以选择公平锁或非公平锁的实现方式。下面将详细介绍 ReentrantLock 的实现原理以及公平锁和非公平锁的区别。 ReentrantLock 实现原理 基本架构 ReentrantLo…...
