Linux 编程学习笔记----过程管理和项目发展(在)
转载请注明出处,http://blog.csdn.net/suool/article/details/38406211,谢谢。
Linux进程存储结构和进程结构
可运行文件结构
例如以下图:
能够看出,此ELF可运行文件存储时(没有调入内存)分为代码区、数据区和未出花数据区三部分。
代码区:存放cpu的运行的机器指令。
数据区:包括程序中的已经初始化的静态变量,以及已经初始化的全局变量。
未初始化数据区:存入的是未初始化的全局变量和未初始化的静态变量。
如今在上面的程序代码中添加一个int的静态变量,结果例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3Vvb2w=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
代码部分添加了4个字节。是int的大小。
进程结构
假设将一个ELF格式可执行文件载入到内存中执行,则将演变成一个或多个进程。进程是Linux事务管理的基本单元,全部的进程均拥有独立的环境和资源。
下图展示一个ELF可运行文件的存储结构和Linux进程基本结构的对比:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3Vvb2w=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
上图仅给出了一个进程的在内存中申请的代码区、初始化数据区、未初始化数据区、堆区、栈区五个部分。
为了更好的管理linux所訪问的资源,系统定义了进程控制块(PCB)结构体来管理每一个进程资源。如图:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3Vvb2w=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
而进程资源分为:
内核空间进程资源和用户空间进程资源
内核空间进程资源即PCB相关的信息。用户空间进程资源包含:通过成员mm_struct映射的内存空间。
进程状态
// 内核进程结构
#define TASK_RUNNING 0 // 就绪
#define TASK_INTERRUPTIBLE 1 // 中断等待
#define TASK_UNINTERRUPTIBLE 2 // 不可中断等待
#define __TASK_STOPPED 4 // 僵死
#define __TASK_TRACED 8 // 暂停
/* in tsk->exit_state */
#define EXIT_ZOMBIE 16
#define EXIT_DEAD 32
/* in tsk->state again */
#define TASK_DEAD 64
#define TASK_WAKEKILL 128
#define TASK_WAKING 256
系统中的每一个进程都必定处于以上所列进程状态中的一种。
TASK_RUNNING表示进程要么正在运行。要么正要准备运行。
TASK_INTERRUPTIBLE表示进程被堵塞(睡眠),直到某个条件变为真。条件一旦达成。进程的状态就被设置为TASK_RUNNING。
TASK_UNINTERRUPTIBLE的意义与TASK_INTERRUPTIBLE类似。除了不能通过接受一个信号来唤醒以外。
__TASK_STOPPED表示进程被停止运行。
__TASK_TRACED表示进程被debugger等进程监视。
EXIT_ZOMBIE表示进程的运行被终止,可是其父进程还没有使用wait()等系统调用来获知它的终止信息。
EXIT_DEAD表示进程的终于状态。
EXIT_ZOMBIE和EXIT_DEAD也能够存放在exit_state成员中。进程状态的切换过程和原因大致例如以下图(图片来自《Linux Kernel Development》)
进程基本属性
进程号(PID)
PID是系统维护的唯一标示一个进程的正整数。进程号是无法在用户层改动的。
在Linux系统中,系统的第一个用户进程是init进程。PID是1,其它的进程的PID依次添加。例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3Vvb2w=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
在应用编程中能够使用getpid()函数获取当前进程的PID.详细參见:http://pubs.opengroup.org/onlinepubs/009695399/functions/getpid.html
父进程号(PPID)
除init进程外的全部进程都是由还有一进程创建的。该进程成为父进程,被创建的进程成为子进程。
PPID一样无法在用户层改动。
使用getppid()函数获取当前进程的父进程号。參见:http://pubs.opengroup.org/onlinepubs/009695399/functions/getppid.html
进程组号(PGID)
和用户管理一样,进程也有自己的进程号(PID)和进程组号(PGID)。进程组是一个或多个进程的集合。他们与同一个作业相关联。能够接受来自同一个终端的各种信号,可是进程组号能够在用户层改动。
使用getpgid()函数获取指定进程的进程组号。详见:http://pubs.opengroup.org/onlinepubs/009695399/functions/getpgid.html
以下一个程序是总和上面三个函数使用的演示样例:
#include<stdio.h>
#include<unistd.h>
int main(int argc,char *argv[])
{
int i;
printf("\tpid\t ppid \t pgid\n"); // 提示信息
printf("parent\t%d\t%d\t%d\n",getpid(),getppid(),getpgid(0)); // 当前进程信息
for(i=0;i<2;i++)
if(fork()==0)
printf("child\t%d\t%d\t%d\n",getpid(),getppid(),getpgid(0)); // 子进程信息
return 0;
}
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3Vvb2w=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
此外,getpgrp()也能够用来获取当前进程的进程组号。
參见:http://pubs.opengroup.org/onlinepubs/009695399/functions/getpgrp.html
会话
会话(session)是一个或多个进程的合集。
系统调用函数getsid()用来获取某个进程会话的SID。
參见:http://pubs.opengroup.org/onlinepubs/009695399/functions/getsid.html
某进程的sid是能够改动的,函数setsid()用于创建新的会话。
here : http://pubs.opengroup.org/onlinepubs/009695399/functions/setsid.html
控制终端
会话和进程组有例如以下特点:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3Vvb2w=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
为了让终端设备驱动程序将信号送到进程。能够调用tcgetpgrp()获取前台进程组的进程组号。返回与打开的终端相关联的前台进程组号。http://pubs.opengroup.org/onlinepubs/009695399/functions/tcgetpgrp.html
tcsetpgrp()函数用来设置某个进程组是前台还是后台进程组。http://pubs.opengroup.org/onlinepubs/009695399/functions/tcsetpgrp.html
假设进程有一个控制终端,则将前台进程组ID设置为pgrpid,这个值应该在用一个会话中的一个进程组的id,參数fileds是控制终端文件描写叙述符。
tcgetsid(*)函数获取当前控制终端的会话首进程的会话id。http://pubs.opengroup.org/onlinepubs/009695399/functions/tcgetsid.html
以下是使用上面的函数演示样例:
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdlib.h>
int main()
{
int fd;
pid_t pid;
pid=fork(); // 创建新进程
if(pid==-1)
perror("fork");
else if(pid>0)
{
wait(NULL);
exit(EXIT_FAILURE);
}
else
{
if((fd=open("/dev/pts/0",O_RDWR))==-1) // 由于是网络终端,在此打开终端以确认
{
perror("open");
}
printf("pid=%d,ppid=%d\n",getpid(),getppid()); // 获取进程号& 父进程
printf("sid=%d,tcgetsid=%d\n",getsid(getpid()),tcgetsid(fd)); // 读取会话sid和终端sid
printf("tcgetpgrp=%d\n",tcgetpgrp(fd)); // 读取终端前台进程
printf("pigd=%d\n",getpgid(getpid())); // 读取进程组的ID
}
}
执行结果:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3Vvb2w=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
进程用户属性
Linux是权限哟有严格控制的操作系统,某个进程拥有真实的用户号(RUID)、真有用户组号(RGID)、有效用户号(EUID)、有效用户组号(EGID)信息。
在Linux系统中,文件的创建者是文件的拥有者,即文件的真有用户号为文件的拥有者号,使用ls -l 命令查看。
进程真有用户号(RUID)
对于进程而言,创建该进程的用户uid即是此进程的真有用户号。使用getuid(0函数获取当前进程的RUID。函数定义在unistd.h中。
详细參见:http://pubs.opengroup.org/onlinepubs/009695399/functions/getuid.html
进程有效用户组号(EUID)
主要用于权限检查。
多数情况下,EUID和UID同样,可是假设可执行文件的setuid位有效,则该文件的拥有者之外的用户在执行程序时,EUID和UID不一样。即当某个可执行文件设置了 setgid位后。不论什么用户(包含root)执行此程序时。其有效用户组EUID为该文件的拥有者。sunch as:
注意setuid位的特殊性,这个以后会专门解说。
进程用户组号(GID)
创建进程的用户所在的组号为该进程的用户组号(GID)。能够调用getgid()函数来获取当前进程的真有用户组号。
详细參见:http://pubs.opengroup.org/onlinepubs/009695399/functions/getgid.html
以下是读取当前进程的UID/GID/EUID/EGID的演示样例程序:
#include<stdio.h>
#include<unistd.h>
int main(int argc,char *argv[])
{
printf("\tuid\tgid\teuid\tegid\n");
printf("parent\t%d\t%d\t%d\t%d\n",getuid(),getgid(),geteuid(),getegid());
if(fork()==0)
{
printf("child\t%d\t%d\t%d\t%d\n",getuid(),getgid(),geteuid(),getegid());
}
return 0;
}
Next
进程管理及控制
Linux 特殊进程
转载请注明出处。http://blog.csdn.net/suool/article/details/38406211,谢谢!
版权声明:本文博主原创文章。博客,未经同意不得转载。
Linux 编程学习笔记----过程管理和项目发展(在)的更多相关文章
- Linux 编程学习笔记----动笔makefile档
Befroe Beginning. 在设置暑假的plan ,关于Linux的书籍如今在看的是ALP和Linux高级程序设计(杨宗德)第三版.在计划中的是Linux高级环境编程. 如今開始关于Linux ...
- Linux 编程学习笔记----文档管理系统
本文从网络上完成的第 Linux在文件系统管理. 1.VFS文件系统概述 linux採用VFS来管理文件系统,并且linux设计的原则之中的一个就是everything is file.因此文件管理系 ...
- Linux 编程学习笔记----ANSI C 文件I/O管理
转载请注明出处:http://blog.csdn.net/suool/article/details/38129201 问题引入 文件的种类 依据数据存储的方式不同,能够将文件分为文本文件和二进制文件 ...
- Linux 编程学习笔记----命令行参数处理
转载请注明出处.http://blog.csdn.net/suool/article/details/38089001 问题引入----命令行參数及解析 在使用linux时,与windows最大的不同 ...
- Linux编程学习笔记(二)
续上个章节,这个章节主要是Linux的远程登录系统操作笔记 一. Linux一般作为服务器使用,但是服务器都是在机房的,所以不可能经常跑到机房去操作系统,所以使用远程登录系统,在Linux的系统一般使 ...
- Linux编程学习笔记(一)
Linux的发展趋势势在必行,国内的服务器的操作系统Linux占到主导地位,不光是操作系统,还有嵌入式系统. 1. 今天就Linux的其中一个版本做一介绍,如下是Centos的版本之间的区别. ins ...
- LINUX编程学习笔记(十四) 创建进程与 父子进程内存空间
1什么是进程:进程是一个执行中的程序 执行的程序: 代码->资源->CPU 进程有很多数据维护:进程状态/进程属性 所有进程属性采用的一个树形结构体维护 ps -a//所有进程 ps - ...
- Linux编程学习笔记 -- Process
进程是一个程序的运行. 在一个程序中执行另一个执程序的方法有两种: 1)system 在shell中执行程序 2)fork + exec 复制一个进程,在进程中用新的程序替换原有的程序 for ...
- LINUX编程学习笔记(十三) 遍历目录的两种方法
1 默认情况下 实际用户和有效用户是一样的 实际用户:执行用户 有效用户:权限用户 getuid() 实际用户 geteuid() 有效用户 chmod u+s 之后 ,其他人执行文件时,实际 ...
随机推荐
- Java 模拟队列(一般队列、双端队列、优先级队列)
队列: 先进先出,处理类似排队的问题,先排的.先处理,后排的等前面的处理完了,再处理 对于插入和移除操作的时间复杂度都为O(1).从后面插入,从前面移除 双端队列: 即在队列两端都能够insert和r ...
- [置顶] android系统功能调用大全
1.从google搜索内容 Intent intent = new Intent(); intent.setAction(Intent.ACTION_WEB_SEARCH); intent.pu ...
- UVA 11768 - Lattice Point or Not(数论)
UVA 11768 - Lattice Point or Not option=com_onlinejudge&Itemid=8&page=show_problem&categ ...
- poj 1198 hdu 1401 搜索+剪枝 Solitaire
写到一半才发现能够用双向搜索4层来写,但已经不愿意改了,干脆暴搜+剪枝水过去算了. 想到一个非常水的剪枝,h函数为 当前点到终点4个点的最短距离加起来除以2.由于最多一步走2格,然后在HDU上T了, ...
- xcode多target
原文:http://www.codza.com/free-iphone-app-version-from-the-same-xcode-project There are more than 15,0 ...
- extjs_11_mvc模式
1.非mvc模式 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWRhbV93enM=/font/5a6L5L2T/fontsize/400/fill/I ...
- 用Javascript评估用户输入密码的强度(Knockout版)
原文:用Javascript评估用户输入密码的强度(Knockout版) 早上看到博友6点多发的一篇关于密码强度的文章(连接),甚是感动(周末大早上还来发文). 我们来看看如果使用Knockout更简 ...
- Mysql 双向关联触发器
双向关联触发器 //增加 delimiter // create trigger InsertDemo AFTER insert on vaccine.demo for each row Begin ...
- 如何添加地图控件到Windows Phone 8的页面中
原文 如何添加地图控件到Windows Phone 8的页面中 本主题介绍了各种方法来添加一个地图控件到Windows Phone 8的项目.该地图控件在Windows Phone的SDK 8.0的库 ...
- ubuntu 12.10 软件更新源列表
ubuntu 12.10正式版已经发布了,国内各大开源软件源也陆续更新了资源.今天分享一下ubuntu 12.10 软件更新源列表. 首先,习惯性的备份一下ubuntu 12.04 原来的源地址列表文 ...