进程控制

1、进程的定义
1.1进程的几种概念

  • 进程是一个具有独立功能的程序关于某个数据集合的一次运行互动
  • 进程是一个程序与其数据一道通过处理机的执行所发生的活动
  • 进程是一个“执行中的程序”,即程序在处理机上执行时所发生的活动,而程序只是行为的一种静态规则
  • 进程是在自身的虚拟地址看空间运行的一个单独的程序

补充:
一个正在执行的进程称为一个作业,而作业可以包含一个或多个进程。
一个或多个进程可以合起来构成一个进程组,一个或多个进程组可以合起来构成一个会话

1.2查看进程信息
Windows:Windows任务管理器
Linux:ps -aux

1.3进程的特性
在Linux系统中,每一个进程都运行在各自的虚拟内存空间中

  • 动态性:进程是程序的执行
  • 并发性:多个程序可以同一时间运行在一个内存空间中
  • 独立性:虽然在一个内存空间中有多个进程在运行,但其实每个进程都运行在各自的虚拟内存空间中,互不干扰。进程是独立获得资源的基本单位。
  • 异步性:各个进程都按照自己的速度在运行,每一个进程的运行速度都是不可预知的。
  • 结构特性:每个进程都有自己的私有空间,这个私有空间分为代码段、数据段和堆栈段

2、进程的基本操作
进程的3种基本状态是运行、等待和结束,对应的进程基本操作是进程创建、进程等待和进程结束。
2.1进程的创建
(1)fork()函数
功能:创建一个新的进程,新进程为当前进程的子进程。
特点:调用一次,返回两次。
调用一次,返回两次:在一个程序中,调用fork()函数后就出现了分叉。在子进程中,fork()返回0,在父进程中返回值为子进程的进程号。但是父进程和与子进程的返回顺序并不是固定的,由于fork()函数是系统调用函数,因此取决于系统中其他进程的运行情况和内核的调度算法

//fork()函数调用
#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);    //返回值类型为pid_t,表示一个非负整数

说明:
若调用fork()函数创建子进程失败,返回-1,并提示错误信息
错误信息有两种形式:
 - EAGAIN:表示fork()函数没有足够的内存用于赋值父进程的二分页表和进程结构数据
 - ENOMEM:表示fork()函数分配必要的内核数据结构时,内存不足

(2)vfork()函数
功能:与fork()相同
区别:在于创建子进程时,

  • fork()函数会复制父进程的资源。包括进程环境、内存资源等
  • vfork()不会复制父进程的所有资源,父子进程共享地址空间。因此,此时在子进程中对虚拟内存空间中变量的修改,实际上是在修改父进程虚拟内存空间中的值

注:使用vfork()时,父进程会被阻塞,需要在子进程中调用_exit()函数退出子进程,不能使用exit()退出函数。

(3)exec()函数族
功能:fork函数是用于创建一个子进程,该子进程几乎是父进程的副本,而有时我们希望子进程去执行另外的程序,exec函数族就提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段在执行完之后,原调用进程的内容除了进程号外,其他全部被新程序的内容替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行脚本文件。
在Linux中使用exec函数族主要有以下两种情况
a. 当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用exec函数族里的任何一个函数让自己重生。
b. 如果一个进程想执行另一个程序,那么它就可以调用fork函数新建一个进程,然后调用exec函数族里的任何一个函数使子进程重生。

2.2进程等待
进程等待是为了同步父进程和子进程,通常需要通过调用wait()等待函数使父进程等待子进程结束。如果父进程没有调用等待函数,子进程就会进入僵尸(Zombie)状态。
僵尸进程:
通常情况下,造成僵尸进程的成因是因为该进程本应该已经执行完毕,但是该进程的父进程却无法完整的将该进程结束掉,而造成该进程一直存在于内存中。
wait()函数系统调用的工作过程:
首先判断子进程是否存在,即是否成功创建了一个子进程。如果创建失败,子进程不存在,则会直接退出进程,并且提示相关错误信息;如果创建成功,那么wait()函数会将父进程挂起,直到子进程结束,并且返回结束时的状态和最后结束的子进程的PID。

  • wait()函数用于等所有的子进程的结束
  • waitpid()函数仅用于等待某个特定进程的结束

2.3进程结束
(1)exit()函数
功能:终止进程

//函数原型
#include <stdlib.h>
void exit(int status);

(2)_exit()函数
功能:终止进程
注:使用vfork()函数创建的子进程在退出时只能使用_exit()函数退出进程。

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

(3)exit()和_exit()的区别:
在调用exit()函数时,会对输入/输出流进行刷新,释放所占用的资源以及清空缓冲区等;而_exit()函数不具备刷新缓冲区等操作的功能

3、线程
线程是进程中的一个实体,是被系统独立调度和分配的基本单位。
一个进程中的若干个线程共享进程中所拥有的全部资源,每个线程本身不拥有系统资源,只拥有很少的必备资源,如程序计数器、寄存器、栈等。
3.1线程的属性
(1)摧毁与初始化线程属性对象
当使用一个线程的属性对象前,需要首先初始化该对象,然后才可以对该线程的属性进行设置和修改。初始化线程属性的函数原型为:

#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);  	//初始化线程属性,必须在创建线程前调用

int pthread_attr_destory(pthread_attr_t *attr);	//摧毁线程属性

参数attr是pthread_attr_t结构体类型的,该结构体类型中定义的attr参数的属性如下:

typedef struct
{
int     detachstate;                线程的分离状态
int     schedpolicy;                线程调度策略
struct sched_param schedparam;      线程的调度参数
int     inheritsched;               线程的继承性
int     scope;                      线程的作用域
size_t  guardsize;                  线程栈末尾的警戒缓冲区大小
int     stackaddr_set;
void *  stackaddr;                  线程栈的位置
size_t  stacksize;                  线程栈的大小
}pthread_attr_t;

(2)设置与获取线程的分离状态
线程的分离状态属性决定了线程是如何结束的。默认情况下,线程是属于可连接状态的。

  • 可连接状态:线程在进程没有退出之前是不会释放线程所占用的资源的
  • 分离状态:线程在终止后会自动释放自身所占资源
//函数原型
#include <pthread.h>

int pthread_attr_setdetachstate(pthread_attr_t* attr,int detachstate);
int pthread_attr_getdetachstate(pthread_attr_t* attr,int detachstate);

参数说明:
attr:指向要设置的线程属性对象的指针
detachstate:分别取PTHREAD_CREATE_DETACHED和PTHREAD_CREATE_JOINABLE表明两种属性

(3)设置与获取线程属性对象的调度策略

#include <pthread.h>
int pthread_attr_setschedpolicy(pthread_attr_t* attr,int policy);
int pthread_attr_getschedpolicy(pthread_attr_t* attr,int policy);

参数说明:
attr:指向要设置的线程属性对象的指针
policy:分别取SCHEDE_OTHER、SCHED_RR和SCHED_FIFO表明三种调度策略

4、进程的特殊操作
(1)获取进程标识
进程ID和父进程ID用PID来标识,在Linux系统中,init进程是所有进程的父进程,其PID指为1.

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

pid_t getpid(void);		//获取进程ID
pid_t getppid(void);	//获取父进程ID

(2)获取用户ID和有效用户ID
Tip:用户ID是从用户的角度来看待,有效用户ID是从操作系统的角度来看待的。
用户ID(UID)用于表示进程的创建者信息,有效用户ID(EUID)用于表示创建进程的用户,在任一时刻对资源和文件都具有访问权限。通常情况下UID和EUID的值是相同的

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

uid_t getuid(void);		//获取当前进程的用户标识
uid_t getupid(void);	//获取当前进程的有效用户标识

(3)获取组ID和有效组ID
进程的组标识GID和有效组EGID代表创建进程的用户组的信息以及用户组对于进程的访问权限的信息

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

gid_t getgid(void);		//获取组ID
gid_t getgid(void);		//获取有效组ID
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值