进程、线程和进程间通信(进程的创建和回收)

进程概念

程序
存放在磁盘上的指令和数据的有序集合(文件)
静态的

进程
执行一个程序所分配的资源的总称
进程是程序的一次执行过程
动态的,包括创建、调度、执行和消亡

进程和程序内容区别

在这里插入图片描述

进程包含的内容:

BSS段:存放程序中未初始化的全局变量
数据段:已初始化的全局变量
代码段:程序执行代码
堆(heap):malloc等函数分配内存
栈(stack):局部变量,函数参数,函数的返回值
进程控制块(pcb):PID, 进程优先级,文件描述符表
下图为面试常问点
在这里插入图片描述

进程类型

交互进程:在shell下启动。可以在前台运行,也可以在后台运行
批处理进程:和在终端无关,被提交到一个作业队列中以便顺序执行
守护进程:和终端无关,一直在后台运行

进程状态

运行态:进程正在运行,或者准备运行
等待态:进程在等待一个事件的发生或某种系统资源(可中断/不可中断)
停止态:进程被中止,收到信号后可继续运行
死亡态:已终止的进程,但pcb没有被释放

在这里插入图片描述

查看进程信息

ps     查看系统进程快照  (查看全部 ps -e ; 查看更详细信息ps -elf)
top    查看进程动态信息(翻页shift + <>/proc  查看进程详细信息

ps 命令详细参数:
-e:显示所有进程
-l:长格式显示更加详细的信息
-f 全部列出,通常和其他选项联用

在这里插入图片描述
在这里插入图片描述
top 查看进程动态信息
shift +> 后翻页
shift +< 前翻页
top -p PID 查看某个进程
ps -elf|grep watching 查看所有看门狗信息

改变进程优先级

nice 按用户指定的优先级运行进程
nice [-n NI值] 命令
NI 范围是 -20~19。数值越大优先级越低
普通用户调整 NI 值的范围是 0~19,而且只能调整自己的进程。
普通用户只能调高 NI 值,而不能降低。如原本 NI 值为 0,则只能调整为大于 0。
只有 root 用户才能设定进程 NI 值为负值,而且可以调整任何用户的进程。

renice   改变正在运行进程的优先级
	renice [优先级] PID

jobs   查看后台进程
bg     将挂起的进程在后台运行
fg      把后台运行的进程放到前台运行

ctrl+z  把运行的前台进程转为后台并停止。
./test &  把test程序后台运行

创建子进程:

子进程概念:
子进程为由另外一个进程(对应称之为父进程)所创建的进程

#include  <unistd.h>
 pid_t  fork(void);

创建新的进程,失败时返回-1
成功时父进程返回子进程的进程号,子进程返回0
通过fork的返回值区分父进程和子进程

//进程创建-fork-示例
pid_t pid;
if((pid = fork()) < 0){
	perror("fork");
	return -1;
}else if(pid == 0){
	printf("child process:my pid is %d\n",getpid());
}else{
	printf("parent process:my pid is %d\n",getpid());
}

要点:1 子进程只执行fork之后的代码
2. 父子进程执行顺序是操作系统决定的。

子进程继承了父进程的内容
父子进程有独立的地址空间,互不影响
若父进程先结束
子进程成为孤儿进程,被init进程收养
子进程变成后台进程

若子进程先结束
父进程如果没有及时回收,子进程变成僵尸进程
子进程创建的练习
在这里插入图片描述

//创建5个子进程
#include <stdio.h>
#include <unistd.h>

int main(){
    pid_t pid;
    int i;    
    for(i=0;i<5;i++){
        pid = fork();
        if(pid<0){
            perror("fork");
            return 0;
        }else if(pid==0){
            printf("child process\n");
            sleep(5);
            break;//子进程创建结束后,跳出子进程,防止循环到i=1时,子进程再生出子进程(即孙进程)
        }else{
            printf("Father process\n");
            sleep(5);
        }
    }

    sleep(100);//使不产生僵尸进程,方便ps查看创建的子进程


}

下图为查看创建出的五个子进程
在这里插入图片描述

错误创建五个子进程 - 示例(原因:子进程没有跳出循环)

#include <stdio.h>
#include <unistd.h>

int main(){
    pid_t pid;
    int i;    
    for(i=0;i<5;i++){
        pid = fork();
        if(pid<0){
            perror("fork");
            return 0;
        }else if(pid==0){
            printf("child process\n");
            sleep(5);
//            break;//子进程创建结束后,跳出子进程,防止循环到i=1时,子进程再生出子进程(即孙进程)
        }else{
            printf("Father process\n");
            sleep(5);
        }
    }

//    sleep(100);//使不产生僵尸进程,方便ps查看创建的子进程
}

此程序创建子进程的效果图(不完整,举例出了i<=2的循环效果)为
在这里插入图片描述

进程的退出

#include <stdlib.h> 
 #include  <unistd.h>
 void  exit(int  status);
 void  _exit(int  status);
 void _Exit(int status);

结束当前的进程并将status返回
exit结束进程时会刷新(流)缓冲区

return 和exit的区别
main函数结束时会隐式地调用exit函数,普通函数return是返回上一级。

//进程结束 - exit - 示例1
#include <stdio.h>
#include <stdlib.h>
int main(void){
	printf("this process will exit");
	exit(0);
	printf("never be displayed");
}
./a.out
this process will be exit

//进程结束 - exit - 示例2
#include <stdio.h>
#include <stdlib.h>
int main(void){
	printf("using exit...\n");
	printf("This is the end");
	exit(0);
}
./a.out
using exit...
This is the end

进程的回收

子进程结束时由父进程回收
孤儿进程由init进程回收
若没有及时回收会出现僵尸进程

//进程回收 - wait
#include  <sys/wait.h>
  pid_t wait(int *status); 

成功时返回回收的子进程的进程号;失败时返回EOF
若子进程没有结束,父进程一直阻塞
若有多个子进程,哪个先结束就先回收
status 指定保存子进程返回值和结束方式的地址
status为NULL表示直接释放子进程PCB,不接收返回值

//进程回收 - wait - 示例
int status;
pid_t pid;
if((pid == fork())<0){
	perror("fork");
	exit(-1);
}else if(pid == 0){
	sleep(1);
	exit(2);
}else{
	wait(&status);
	printf("%x\n",status);
}

子进程通过exit/_exit/return 返回某个值(0-255)
父进程调用wait(&status)回收

WIFEXITED(status)  判断子进程是否正常结束
WEXITSTATUS(status)获取子进程返回值
WIFSIGNALED(status)判断子进程使用否被信号结束
WTERMSIG(status)   获取结束子进程的信号类型
//进程回收 - waitpid
#include  <sys/wait.h>
  pid_t waitpid(pid_t pid, int *status, int option);

成功时返回回收的子进程的pid或0;失败时返回EOF
pid可用于指定回收哪个子进程或者任意子进程
status指定用于保存子进程返回值和结束方式的地址
option指定回收方式,0或WNOHANG
参数:
pid
pid>0时,只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。
pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。
pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。

options

options提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED两个选项,这是两个常数,可以用"|"运算符把它们连接起来使用

WNOHANG :若由pid指定的子进程未发生状态改变(没有结束),则waitpid()不阻塞,立即返回0
WUNTRACED: 返回终止子进程信息和因信号停止的子进程信息

wait(wait_stat) 等价于waitpid(-1,wait_stat,0)

//进程回收 - waitpid - 示例
waitpid(pid, &status, 0);
waitpid(pid, &status, WNOHANG);
waitpid(-1, &status, 0);
waitpid(-1, &status, WNOHANG);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值