Linux 进程管理与程序开发1

8.1进程的环境及进程属性

8.1.1程序、进程与进程资源

进程是Linux系统下资源管理的基本单元,线程是Linux系统调度的基本单元。注意区分。
进程资源由两部分组成:内核空间的进程资源和用户空间的进程资源。
内核空间进程资源即PCB(进程控制块,通过struct task_struct来管理)相关的信息。包括进程控制块本身、打开的文件表项、当前目录、当前终端、线程基本信息。可访问内存地址空间、PID、PPID、UID、EUID等。内核通过PCB可以访问该进程的所有资源。这些资源只能通过系统调用才能访问。这一资源在当前进程退出时,只能由另一个进程回收。
用户空间的进程资源包括:通过成员mm_struct映射的内存空间。实质就是进程的代码段、数码段、堆、栈,以及可以共享访问的库的内存空间。这些资源进程可以直接访问。这些资源在进程退出时主动释放。在进程运行时,可以通过文件/proc/[pid]查看进程状态。
/proc[pid]

8.1.2进程状态

在Linux2.6内核中,用户级进程拥有:就绪/运行状态、等待状态(可被中断打断)、等待状态(不可被中断打断)、停止状态、僵死状态。
TASK_RUNNING:正在运行或就绪状态。就绪状态指申请到除了CPU以外的其他所有需要的资源。
#define . 0
TASK_INTERRUPTIBLE:处于等待队伍中,等待有效资源时唤醒,但可以被中断唤醒。
1
TASK_UNINTERRUPTIBLE:处于等待队伍中,等待有效资源时唤醒,但不可以被中断唤醒。
2
TASK_ZOMBIE:进程资源被用户空间释放,但内核中的PCB并没有被释放,等待父进程回收。
4
TASK_STOPPED:进程被外部程序暂停(如收到SIGSTOP信号),当再次允许时继续执行,因此处于这一状态的进程可以被唤醒。
8
用户级进程的状态转换关系:
在这里插入图片描述

系统内核进程状态略有差异。
#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
#define TASK_STOPPED 4
#define TASK_TRACED 8 //跟踪状态
#define EXIT_ZOMBIE 16
#define EXIT_DEAD 32

8.1.3进程的基本属性

与进程本身相关的属性包括进程号(PID),父进程号(PPID),进程组号(PGID)。

1.进程号(PID)

进程号是系统维护的唯一标识一个进程的正整数。进程号在用户层无法修改。
在linux操作系统中,系统的第一个用户进程为init进程,他的PID为1,其他进程的PID以此增加,通过“ps aux”命令查看当前系统所有进程的基本属性。
在应用编程中,通过
extern __pid_t getpid(void);
获得当前进程的pid。

vicli@www.100ask.org:~/2_linux_program/_8_process$ cat getpid_exp.c 
#include "stdio.h"
#include "unistd.h"

int main(int argc, char *aargv[])
{
	printf("the current program's pid is %d\n", getpid());
	return 0;
}

2父进程号(PPID)

任何进程(除init进程)都是由另一个进程创建的,该进程称为被创建进程的父进程,被创建的进程称为父进程。父进程号无法在用户层修改,父进程的进程号即为子进程的父进程号,通过
extern __pid_t getppid(void);
获得。

3.进程组号(PGID)

在linux系统中,每个用户都拥有用户号(UID)和用户组号(GUID)。和用户管理一样,进程也拥有自己的进程号和进程组号。进程组是一个或多个进程的集合。他们与同一作业相关联,可以接受来自同一终端的各种信号。每个进程都拥有唯一的进程组号,进程组号可以在用户层修改。
通过
extern __pid_t getpgid(__pid_t __pid);
获得。
参数pid为要获得的进程组号的进程号。如果为0表示获取当前进程组号,否则为指定的进程的PGID。

另外可以通过
pid_t getpgrp(void);
获得。
每个进程组都可以有一个组长进程,组长进程的进程组号等于其进程号。但组长进程可以先退出,即只要在某个进程组中有一个进程存在,该进程组就存在,与其组长进程是否终止无关。进程组的最后一个进程可以终止,或者转移到另一个进程组。
将某个进程加到某个进程组的系统调用函数
int setpgid(pid_t pid, pid_t pgid);
第一个参数为欲修改进程的PGID的进程PID,第二个参数为新的进程组号,如果这两个参数相等,则由pid指定的进程变成进程组组长,如果pid为0,则修改当前进程的PGID。如果PGID为0,则由pid指定的进程的PID将用于进程组号PGID。
一个进程只能为自己或子进程设置进程组号PGID,在他的子进程调用了exec函数后,就不能再改变该进程的进程组号。
一般来说,在shell终端下运行的程序的第一个进程将成为新的进程组组长。

4.会话

会话(session)是一个或多个进程组的集合,系统调用函数
extern __pid_t getsid(__pid_t __pid);
获得某个进程的会话号SID。
如果pid为0,返回调用进程的会话号SID。一般,该值等于进程组号PGID。如果pid并不属于调用者所在的会话,则调用者就不能获得SID。
某进程的会话SID是可以修改的。调用
extern __pid_t setsid(void);
创建新的会话。
如果调用进程已经是一个进程组的组长,则此函数返回错误。为了杜绝这种情况发生,通常会先调用fork创建子进程,然后使其父进程终止,而子进程继续,在子进程中调用此函数。
如果调用此函数的进程不是一个进程组的组长,则此函数会创建一个新会话。

  1. 该进程会变成新会话首进程,会话首进程是创建该会话的进程。
  2. 该进程成为一个新的进程组的组长进程,新进程组PGID是该调用进程的PID。
  3. 该进程没有控制终端,如果在调用setsid之前该进程就有一个控制终端,那么这种联系也会被切断。

5控制终端

https://blog.csdn.net/qq_27825451/article/details/101307195
控制终端的一些内容。
或者参考上一篇博客有所介绍。

会话和进程组有以下特点:

  1. 一个会话可以有一个控制终端,建立与控制终端连接的会话首进程被称为控制进程。
  2. 一个会话中的几个进程组可被分为一个前台进程和几个后台进程,如果一个会话有一个控制终端,则它有一个前台进程组。
  3. 无论何时键入终端的中断键,都会将中断信号发送给前台进程组的所有进程。如果终端检测到调制解调器已经断开连接,则将挂断的信号发送给控制进程(会话首进程)。

为了让终端设备驱动程序清楚的将信号(终端输入和终端产生的)送到那些进程,可以调用函数
pid_t tcgetpgrp(int filedes);
获取当前前台进程组的进程组号。
函数tcgetpgrp返回与打开的终端(由filedes指定)相关联的前台进程组的进程组号。

pid_t tcsetpgrp(int filedes, pid_t pgrpid)用来设置某个进程组是前台进程还是后台进程。如果进程有一个控制终端,则将前台进程组的ID设置为pgrpid,pgrpid的值应该在同一会话中的一个进程组的ID,filedes为控制终端的文件描述符。

pid_t tcgetsid(int filedes)可以获取控制终端的会话首进程的会话ID。

8.1.4 进程用户属性

linux是权限有严格控制的操作系统,某个进程拥有真实的用户号(RUID),真实的用户组号(RGID),有效用户号(EUID),有效用户组(EGID)信息。在讲到进程的用户时,需要将文件的拥有者以及拥有者组加以区别。
在linux操作系统中,文件的创建者为文件的拥有者,即文件的真实用户号为文件的创建者号。

1.进程真实用户号(RUID)

对于进程而言,创建该进程的用户的UID(执行此程序的用户)为此进程的真实用户号。可以用过调用
extern _uid_t getuid(void)
来获得当前进程的真实用户号(RUID)。

2. 进程有效用户号(EUID)

EUID主要用于权限检查,多数情况下,EUID和UID相同。如果可执行文件的setuid位有效,则该文件的拥有着之外的用户运行该程序时,EUID和UID不相同;即当可执行文件设置了setuid位后,任何用户(包括root用户)运行此程序时,其有效用户组EUID为该文件的拥有者。
在设置了setuid位后,其他用户在执行该文件时具有该文件拥有者对该文件的访问权限。因此,如果设置了setuid位的可执行文件,则其他用户在执行该程序时,其EUID为该可执行文件的拥有着的ID值。
可以通过调用
extern __uid_t geteuid(void);
来获得当前进程的EUID。

3.进程用户组号(GID)

创建进程的用户所在的组号为该进程的进程用户组号(GID),可以通过
extern __uid_t getgid(void);
来获得当前进程的真实用户组号(GID)。

4. 有效进程用户组号(EGID)

一般情况下,EGID和GID相同,但是,当某可执行文件设置了setgid位,那么任何用户运行此程序时,其有效用户组号EGID为该文件的拥有者所在组。其原理与EUID类似。
通过调用
extern __uid_t getegid(void);
可以获得当前进程的有效用户组号(EGID)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值