4.5、进程相关

标签: Linux  嵌入式  C语言

进程:程序执行时,所需要的资源的集合总称
程序的一次执行过程

程序:一些指令的集合,存在在磁盘空间中,是静态的

进程:动态的执行过程(创建、调度、执行、消亡),指令的执行过程

程序包含
1、用户数据段
2、正文段

进程包含的内容
1、用户数据段:存放的是全局变量、常数以及动态数据分配的数据空间
2、正文段:存放的是程序中的代码
3、系统数据段

系统数据段包含
1、进程控制块
2、cpu中pc寄存器
3、堆栈

进程控制块PCB
1、进程号 pid(在系统中进程的唯一识别)
2、进程优先级、状态
3、进程用户
4、文件描述符表

linux下进程的类型
1、交互进程(终端):依赖与终端,与用户进行交互
2、批处理进程:根据作业调度方式一次去执行多个进程
3、守护进程:通常跟随系统执行,在执行时与终端没有交互,在后台自己执行,系统关闭时才结束进程的执行

进程的执行状态
1、运行态(就绪态):当前进程正在执行(被cpu调度)或等待着被执行(等待被cpu调度)
2、等待态:执行被打断,等待某个需要的资源产生或被某个条件**,当条件满足可以带到运行态: 不可中断等待 、可中断等待
3、停止态:当前进程被中断(停止),等待信号**,可回到运行态
僵尸态:进程已结束,但是有资源未被释放(pcb)

在这里插入图片描述
在这里插入图片描述

进程终端相关命令
ps 查看系统运行的进程
ps -ef查看系统中所有运行进程
ps -ef|grep a.out查看指定名字进程
top动态查看系统中运行的进程
/proc目录中也能查看到执行的进程说明
ctrl + z把进程放到终端后台挂起
jobs查看终端后台进程
bg把终端后台挂起的进程执行起来
fg把终端后台进程放到前台执行
如果进程直接想在后台执行 :在执行程序后面 + &
kill 发送一个信号给进程pid
nice设置某个进程以指定的优先级运行(最高优先级只能为0)
renice

相关函数
进程号(Process Identity Number,PID)
父进程号(Parent Process ID,PPID)

1、创建进程函数
pid_t fork(void);//创建一个进程,创建出来的进程是当前进程的子进程,执行创建的进程就是父进程
用fork函数创建进程时:会把父进程中几乎所有内容复制给子进程(子进程的代码内容和父进程一样),子进程从fork的下一句开始执行
返回值:子进程创建成功,在父进程中返回子进程的pid进程号;在子进程返回0—使用PID判断就可以让父子进程执行不同的程序
进程创建后:父子进程有自己独立的空间(各自能独立执行)
父进程和子进程的执行顺序:执行顺序随机执行(cpu调度的顺序)

获取PID
父进程PID—getppid()
本进程PID—getpid()

父子进程结束
1)、如果父进程先结束
子进程会变成孤儿进程,会被init进程收养
子进程会变成后台进程
2)、如果子进程先结束(子进程的资源释放是由父进程去执行)
如果父进程不回收资源,会变成僵尸进程

2、结束进程函数
void exit(int status(0~255));//结束进程,在调用相应函数之后的内容都不执行
void _exit(int status);//结束进程
exit结束进程时会清空缓冲区(文件缓冲区)
_exit结束进程不会清空缓冲区
参数:调用时告诉父进程当前进程的结束状态

进程执行时先执行一个启动例程,去获取到进程执行的相应参数,然后交给主函数,由主函数根据相应的内容执行程序代码(exit(main()))

结束进程的方式
1)、main函数返回(return)
2)、调用exit函数
3)、调用信号结束

3、等待接收子进程状态
pid_t wait(int *wstatus);//阻塞等待接收任意子进程状态(接收的子进程随机)
参数:用来接收子进程返回状态的地址(子进程的返回状态存放到参数地址中)
返回值:表示接收的是哪个子进程(pid)

pid_t waitpid(pid_t pid, int *wstatus, int options);//以指定方式、指定接收某个子进程状态
参数:1)、指定接收哪个子进程的结束状态
-1表示接收任意一个子进程
>0表示接收指定的一个子进程
3)、按指定方式等待接收
0表示阻塞方式等待接收
WNOHANG表示子进程如果没结束,就返回,不会等待(非阻塞)
2)、用来接收子进程返回状态的地址(子进程的返回状态存放到参数地址中)
返回值:如果以WNOHANG接收子进程状态,但(pid参数)子进程没有结束,就返回0,其他同上(wait)
wait(NULL) == waitpid(-1,NULL,0)

4、exec函数族(让当前进程执行的代码进行替换,替换成你想要的可执行程序)
*int execl(const char *path, const char arg, …/* (char *) NULL */);
参数: 1)、要替换的可执行程序的路径(包括可执行程序的名字)(以字符串形式表示,这里需要字符串的地址)
2)、 3)、4)、…NULL(从第二个参数开始)(表示以哪种方式去执行新的代码内容,在当前进程中执行)
2)、需要给定执行的可执行程序是什么(名字)(告诉这个函数,你去执行的可执行程序的名字)
3)、执行这个进程所需要的第一个 选项(方式、参数)
4)、执行这个进程所需要的第二个 选项
。。。。。。。。
规定最后一个参数结束后,再加一个参数为(NULL)表示执行可执行程序的参数结束
例:a = execl("/bin/ps","ps" , "-ef",NULL); ps -ef
返回值:只有出错才有返回值,返回-1;

int execlp(const char *file, const char *arg, …/* (char *) NULL */);
参数:1)、要替换的可执行程序的名字(这个函数执行时已经指定了一个路径,它会从指定路径中寻找可执行程序)
其他参数同execl
例:execl(“ps”,“ps” , “-ef”,NULL); ps -ef用这个函数时 第一个参数和第二个参数一样

int execv(const char *path, char *const argv[]);
参数:1)、要替换的可执行程序的路径(包括可执行程序的名字)(以字符串形式表示,这里需要字符串的地址)
2)、指针数组,数组中存放的字符串指针要指定一个执行新的可执行程序的说明(分别用数组中每个元素来存储)
通过数组形式把需要的参数字符串地址存储起来,传入execv函数中
例:
char * buf[10];//buf[0]存储要去执行程序名字,后面下标中可存可执行程序所需的参数,在参数完了之后的一个下标存NULL表示结束

buf[0] = “ps”;buf[1] = “-ef”;buf[2] = NULL
execv("/bin/ps",buf);ps -ef

int execvp(const char *file, char *const argv[]);
参数:1、要替换的可执行程序的名字(这个函数执行时已经指定了一个路径,它会从指定路径中寻找可执行程序)
其他同上(execv)
例:
char * buf[10];//buf[0]存储要去执行程序名字,后面下标中可存可执行程序所需的参数,在参数完了之后的一个下标存NULL表示结束
buf[0] = “ps”;buf[1] = “-ef”;buf[2] = NULL
execv(buf0,buf);ps -ef

进程简单使用示例

/*****************************************************************
*   Copyright (C) 2018 Sangfor Ltd. All rights reserved.
*   
*   文件名称:process1.c
*   创 建 者:yinfei-hu
*   创建日期:2018年08月29日  星期3 17时20分55秒
*   功能描述:进程的简单使用
*
*****************************************************************/
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	pid_t pid;
	char buff[64], *cmd = "exit"*cmd1 = "Hello!"; 
	
	pid = fork();
	
	if (-1==pid) {
		perror("Create process fail!");
		return 0;
	} 
	else if (0==pid) {							
		while(1) printf("This is the child process !\n");
	}
	else 
	{										
		printf("Parent process! child process id: %d\n", pid);
		printf("This is the parent process!\n");
	}
 return 0;
}

守护进程
1、通常跟随系统运行而执行,系统关闭而结束(linux绝大多数进程都是守护进程)
2、始终在后台运行
3、脱离于终端
4、通常是周期性的做某个事情,或等待事件产生然后做相应操作

在linux中,以进程组与会话的方式管理进程
1、进程组:由进程创建出来时,分配一个进程组方便管理(一个进程创建就创建一个进程组)

2、会话:由一个或多个进程组的集合,在会话中创建进程,进程就属于当前会话,创建会话的进程就叫做会话组长

终端关闭,相关进程都会结束

守护进程创建
1、创建子进程,脱离终端,让子进程在后台运行

   if(fork() > 0){
       exit(0);
   }

2、创建新会话

pid_t setsid(void);//创建新会话函数
//返回值:成功返回创建的新会话id,失败返回-1
   if(setsid() < 0){
       exit(0);
   }

3、修改访问的默认目录

int chdir(const char *path);//修改当前进程的默认目录
//参数:修改之后的工作目录的路径
//返回值:成功返回0,失败返回-1
  if(chdir("/tmp") < 0){
       exit(0);
   }

修改工作路径:你要能够操作(目录的权限)得到你修改的目录(如果你要通过进程去读取目录里面文件内容,进程需要具备目录的读权限)

4、修改文件权限掩码

mode_t umask(mode_t mask);//设置当前进程的文件权限掩码(其他进程管不了文件权限掩码)
//参数:通过mask设置文件权限掩码(umask = mask&0777)111 111 111
   umask(0);//文件权限掩码值设置为0,只对当前进程有效

5、关闭文件描述符–输入输出之类的

int getdtablesize(void);//获取当前进程打开的文件的最大值
for(i = 0;i <getdtableszie();i++)


   close(i);

守护进程示例

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

int main(){
    if(fork() > 0){
        exit(0);
    }
    setsid();
    chdir("/tmp");
    umask(0);
  
    int i;
    for(i = 0;i < getdtablesize();i++){
        close(i);
    }

    FILE * fp = fopen("./text.txt","a+");

    while(1){
        char buf[10] = "hello\n";

        fwrite(buf,1,strlen(buf),fp);
        
        fflush(fp);

        sleep(1);
    }

    return 0;
}
版权声明:本文为qq_41110647原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_41110647/article/details/106421360

智能推荐

使用欧几里得算法解决问题——求字符串的最大公因子(力扣第1071题)(JavaScript解法)

1、欧几里得算法的思想 基于辗转相除法的原理,具体做法:用较大数除以较小数,再用出现的余数(第一个余数)去除除数,,再用出现的余数(第二个余数)去除第一个余数,如此仿佛,直到最后一个余数为0 2、算法流程 3、JavaScript实现欧几里得算法 4、使用欧几里得算法解决问题 力扣1071字符串的最大公因子 题目描述: 对于字符串 S 和 T,只有在 S = T + … + T(T ...

spring与redis整合和序列化问题

spring与redis整合 首先用docker下载redis 下载:docker pull redis 运行:docker run -d -p 6379:6379 --name myredis docker.io/redis 连接redis Desktop Manager 然后开始在springboot上开始配置 application.yml: 自动配置好StringRedisTemplate...

CentOS 7配置南大docker镜像

文章目录 CentOS 7配置南大docker镜像 0.帮助页面 1.系统要求 2.卸载旧版本(没有旧版本可跳过) 3.安装方式 4.准备工作 5.可选操作 Stable Test Nightly 6.安装docker引擎 7. (可选)修改配置文件防止与xshell连接冲突 8.启动docker CentOS 7配置南大docker镜像 0.帮助页面 南大docker源:https://mirr...

Qcon演讲纪实:详解如何在实时视频通话中实现AR功能

2018年4月20日-22日,由 infoQ 主办的 Qcon 2018全球软件开发大会在北京如期举行。声网首席 iOS 研发工程师,iOS 端移动应用产品设计和技术架构负责人龚宇华,受邀分享了《基于 ARkit 和 ARcore,在实时视频通话中实现 AR 功能》,在演讲中剖析了 AR 与 VR 差异,ARKit 的工作原理,以及逐步讲解如何基于 ARKit 与声网Agora SDK 创建 AR...

POJ2348 UVa10368 HDU1525 Euclid's Game【博弈】

Euclid's GameTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4106    Accepted Submission(s): 1947 Probl...

猜你喜欢

使用Breeze.js编写更好的查询

这篇文章是由同行评审Agbonghama柯林斯 。 感谢所有SitePoint的审稿作出SitePoint内容也可以是最好的! 数据量正在迅速发展,他们正在变得越来越复杂,维护。 许多开发人员希望避免由数据问题他们的工作过程中造成的问题和头痛。 一个使我们的工作更轻松的图书馆是Breeze.js 。 在这篇文章中,我们将讨论我们如何能够写出更好的查询与Breeze.js。 但是首先,我们应该知道什...

Netty框架构建Nio编程

~~~ 随手点赞,养成习惯 ~~~ 为什么选择Netty框架 Netty是业界最流行的NIO框架之一,它的健壮性、功能、性能、可定制性和可扩展性在同类框架中都是首屈一指的。 优点: ① API使用简单,开发门槛低 ②功能强大,预置了多种编解码功能,支持多种主流协议 ③ 定制能力强,可以通过ChannelHandler对通信框架进行灵活地扩展; ④性能高,通过与其他业界主流的NIO框架对比,Nett...

【JZOJ5262】【GDOI2018模拟8.12】树(DP,性质题)

Description Solution 首先我们可以知道两个性质:1、路径u-v和路径v-w可以合并为路径u-w;2、路径u1-v1加路径u2-v2和路径u1-v2加路径u2-v1是等价的(就是起始点和终点可以互换) 那么知道这些性质之后就很好做了。我们只用知道每个点多少次做起点和多少次做终点。 我们设f[i]表示满足i子树的需求i上的值要是多少。 那么枚举i的所有儿子,判断a[i]-f[i],...

【String-easy】541. Reverse String II 反转的元素,有反转个数和间隔

1. 题目原址 https://leetcode.com/problems/reverse-string-ii/ 2. 题目描述 3. 题目大意 给定一个字符串,和字符串的间隔k, 这个k表示每k个数反转一次,然后再间隔k个元素再反转k个元素。 4. 解题思路 只要按照间隔去反转就可以了。然后间隔k个元素不反转是通过让i每次递增 2*k完成的。 5. AC代码 6. 相似题型 【1】344. Re...

【C语言笔记结构体】

我们都知道C语言中变量的类型决定了变量存储占用的空间。当我们要使用一个变量保存年龄时可以将其声明为int类型,当我们要使用一个变量保存某一科目的考试成绩时可以将其声明为float。 那么,当我们要做一个学生信息管理系统时,需要保存学生的姓名、学号、年龄等信息,该怎么做呢? 如当要保存三个学生的信息时, 方法一是: 方法二是: 显然,方法二跟更清晰,因为它把name、num、age都集成在一个模板,...