06,进程


基本命令:

ps:查看当前终端所启动的进程信息;
ps -aux //ps -aux | more:查看所有进程详细信息,并分屏显示
ps -ef // ps -ef | more:以全格式的方式显示所有进程信息
kill -9 进程号:杀死指定的进程

目前主流的操作系统都支持多进程,如果进程A启动了进程B,那么进程A叫做进程B的父进程,
进程B叫做进程A的子进程;

PID:进程的编号,是操作系统中对进程的唯一标识,进程编号的数据类型一般是int类型;
但是从0开始使用,操作系统一般会采用延迟重用的策略进行管理,保证在任意时刻进程号都是唯一的;

getpid():获取当前进程编号
getppid():获取当前进程父进程编号
getuid():获取当前用户编号
getgid():获取当前用户所在组编号

gcc -E getpid.c -o getpid.i
生成预处理文件,可在文件中查找各种宏定义变量的最终类型;
比如查找 pid_t 的类型 ==== /pid_t

***************************************************
进程的创建
#include <unistd.h>
pid_t fork(void);

函数功能:
    主要用于以复制当前正在调用进程的方式创建新进程,
    其中新创建出来的进程叫做子进程,当前正在调用的进程叫做父进程;

成功:父进程返回子进程的进程号,子进程返回0;
失败:父进程返回-1,没有子进程;

注意:使用fork函数创建的子进程之后,父子进程的执行先后顺序由系统决定;
没有必然的先后顺序

父子进程的执行方式:
    1.对于fork函数调用之前的代码来说,父进程执行一次;
    2.对于fork函数调用之后的代码来说,父子进程各执行一次;
    3.对于fork函数调用的返回值来说,父子进程各自返回一个,
    其中父进程返回子进程的进程号,子进程返回0;

父子进程之间的关系:
1.父进程启动了子进程,父子进程同时执行;如果子进程先于父进程结束,
会给父进程发信号,父进程负责回收子进程的资源;

2.如果父进程先结束,则子进程就会变成孤儿进程,此时子进程会变更父进程;
一般认定init为新的父进程,init进程收养了孤儿进程,因此被叫做孤儿院进程;

3.如果子进程先结束,但是由于各种原因父进程没有收到子进程发来的信号,
也就是不能回收子进程的资源,此时子进程就会变成僵尸进程;

父子进程之间的复制关系:
使用fork函数创建子进程后,子进程会复制父进程中除了代码区之外的其他内存区,
而代码区和父进程共享;

使用fork函数创建子进程后,子进程会复制父进程中的文件描述符总表,
但不会复制文件表数据结构,因此父子进程对应的是同一个文件表结构;

*****************************************
正常终止进程的方式:

1.执行了main函数中的return语句;
2.调用exit函数终止进程;
3.调用_exit()/_Exit()函数终止进程;
4.最后一个线程调用;
5.最后一个线程调用了pthread_exit()函数;


非正常终止进程的方式

1.采用信号终止进程;
2.最后一个线程被其他线程取消;

**************************************

#include <unistd.h>
void _exit(int status);  UC函数

#include <stdlib.h>  标C函数
void _Exit(int status);

参数:
    主要用于返回给父进程作为当前进程的退出状态信息;
    若父进程想要获取该退出状态信息,则需要使用wait系列函数中的一个;

函数功能:
    主要用于立即终止当前正在调用的进程,在终止的同时,会关闭所有属于该进程的文件描述符;
    让该进程的所有子进程变更父进程为init进程;给该进程的父进程发送SIGCHLD信号

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

函数功能:
    主要用于引起正常进程的终止,参数 status & 0377 的结果会被返回给父进程;
    作为当前进程的退出状态信息,父进程若要获取该信息,也得调用wait系列函数中的一个;

该函数在终止进程时,会引起atexit()和on_exit函数所注册函数的调用;

#include <stdlib.h>
int atexit(void (*function)(void));

函数功能:
    主要用于注册/单独保存  参数指定的函数,该函数会在正常进程终止时被调用;
    而正常终止进程的方式主要有两种:
    1.调用exit()函数; 2.执行了main函数中的return;

成功:返回0;失败:返回-1;


****************
函数的等待,回收

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);

成功:返回终止子进程的进程号;失败:返回-1;

函数功能:
    主要用于挂起当前正在调用进程的执行,直到该进程中的任意一个子进程终止为止;
    当参数不为空时,该函数会将获取到的退出状态信息填充到该参数指定的int类型存储空间中;

为了正确解析该退出状态信息,需要使用一下的带参宏:

WIFEXITED(*status):判断子进程是否正常终止;
正常终止调用有:_exit()/exit()/执行了main中的return;

WEXITSTATUS(*status):获取子进程的退出状态信息;


pid_t waitpid(pid_t pid,int *status,int options);

第一个参数:进程的编号;如果是-1,则等待任意一个子进程状态发生改变
第二个参数:同上
第三个参数:等待的方式,默认:0即可

成功:返回终止子进程的进程号;失败:返回-1;
函数功能:主要用于等待参数指定的子进程状态发生改变;

#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);

函数功能:
    类似fork函数,都是创建当前正在调用进程的子进程,有关细节,
    返回值以及可能出错的原因参考fork函数
    该函数是一种特殊的克隆,在创建新的进程时不会去复制父进程中的叶表信息;
    该函数创建完毕子进程后会挂起父进程,直到子进程终止或者调用exec系列函数为止;
    也就保证了子进程先执行;
    
    在子进程终止/调用exec系列函数之前,子进程共享所有内存空间和父进程,包括栈区
    子进程不能从当前函数中返回,也不能调用exit()函数,但是可以调用_exit()函数;

exec系列函数
#include <unistd.h>
int execl(const char *path, const char *arg, ...);

第一个参数:字符串形式的路径名
第二个参数:字符串形式的参数,一般指定具体的执行方式
第三个参数:可变长参数

返回值:成功没有返回值,失败返回-1;
函数功能:主要用于执行参数指定的文件指令;

#include <stdlib.h>
int system(const char *command);
ex: int res = system("ls -l");

函数功能:主要用于执行参数指定的shell命令;
返回值:成功 返回命令的退出状态信息,失败 返回-1;





进程之间的通信:
1.文件
2.信号
3.管道
4.共享内存
5.消息队列  重点
6.信号量集
7.网络     重点

4,5,6 统称为XSI IPC通信方式



********管道实现进程之间的通信********

管道:本质上还是以文件作为媒介,只是该文件比较特殊,叫做管道文件而已;

分为两大类:
有名管道:可以用于任意两个进程之间的通信
无名管道:主要用于父子进程之间的通信


有名管道时间进程之间的通信:

mkfifo a.pipe:创建管道文件


#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode/*权限 如0664*/);

函数功能:用于创建参数指定的有名管道文件






********使用共享内存实现进程之间的通信********

共享内存:本质上是一块由系统内核维护的内存空间,该内存空间被共享在两个进程之间;
从而通过读写实现通信;

通信模型:
1.获取key值,使用ftok函数;
2.创建共享内存,使用shmget函数;
3.挂接共享内存,使用shmat函数;
4.访问共享内存;
5.脱接共享内存,使用shmdt函数;
6.如果不再使用,则删除共享内存,使用shmctl函数;




#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);

第一个参数:字符串形式的路径名; 必须存在并且可以访问
第二个参数:项目编号;必须是非0 取底八位二进制位

返回值:成功返回key_t类型的key值,失败返回-1;

函数功能:主要用于根据路径名和项目编号来生成key值

****注意****
使用相同的文件路径和项目编号时,生成的key值也相同;






#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);

第一个参数:
第二个参数:共享内存的大小
第三个参数:具体的操作标志
            IPC_CREAT:若不存在则创建,存在则打开
            IPC_EXCL:与PIC_CREAT搭配使用,若存在则创建失败
            0:获取已经存在的共享内存
返回值:

函数功能:创建/获取一个共享内存

****注意****

当前创建新的共享内存时,需要在第三个参数中通过按位或的方式来指定权限信息;









********使用信号量集实现进程之间的通信********

信号量的基本概念:
    本质上是一个计数器,用于控制同时访问同一种共享资源的进程/线程个数


信号量的工作方式:
1.首先初始化信号量为最大值
2.当有进程申请共享资源时,信号量的数值减1;
3.当信号量的数值为0时,申请共享资源的进程进入阻塞状态;
4.当有进程释放共享资源时,信号量的数值加1;
5.只要信号量的数值>0,则阻塞的进程可以继续抢占资源,抢不到的进程继续阻塞;


什么是信号量集:
本质上就是若干个信号量组成的集合;用于控制多种共享资源分别被同时访问的进程/线程个数


通信模型:
1.获取key值,使用ftok函数;
2.创建/获取信号量集,使用semget函数;
3.初始化/操作信号量集,使用semctl/semop函数;
4.如果不再使用,则删除信号量集,使用semctl函数;、


相关函数的解析:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg);
第一个参数:key值ftok函数的返回值
第二个参数:信号量集的大小,也就是信号量的个数;0 - 获取已经存在的信号量集
第三个参数:具体的操作标志
            IPC_CREAT 若存在则打开,若不存在则创建
            IPC_EXCL  和IPC_CREAT搭配使用,若存在则创建失败
                      0 - 获取已经存在的信号量集

返回值:成功返回信号量集,失败返回-1;

函数功能:主要用于创建/获取信号量集;

注意:当创建新的型号量集时,需要在第三个参数中通过按位或的方式指定权限信息;



#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semctl(int semid, int semnum, int cmd, ...);
第一个参数:信号量集的ID,semget函数的返回值
第二个参数:信号量集的下标,从0开始
第三个参数:具体的操作命令
            IPC_RMID  删除信号量集,忽略第二个参数,不需要第四个参数;
            SETVAL     使用第四个实参给下标为semnum的信号量初始化
            
第四个参数:可变长参数,是否需要取决于cmd

返回值:成功返回信号量集,失败返回-1;

函数功能:主要用于控制参数指定的信号量集;






#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semop(int semid, struct sembuf *sops, unsigned nsops);

第一个参数:型号量集的ID,semget函数的返回值;
第二个参数:结构体指针,可以指向结构体变量,也可以指向结构体数组;
第三个参数:结构体变量的个数;
            当第二个参数指向结构体变量时,该参数的数值为1;
            当第二个参数指向结构体数组时,该参数为数组元素个数;


主要功能:主要用于操作指定的信号量集


struct sembuf sops[2];
sops[0].sem_num = 0;        /* 信号量集的下标*/
sops[0].sem_op = 0;         /* >0:增加  <0:减少  =0 不变 */
sops[1].sem_flg = 0;        /* 操作标志,默认0*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值