进程、、、

来源:互联网 发布:加藤小雪相貌知乎 编辑:程序博客网 时间:2024/06/05 22:20
1.进程属性
进程与程序:
程序:磁盘文件,格式:elf   readelf  a.out
进程:elf文件执行过程,4G虚拟空间,代码+初始化数据段+未初始化数据段+堆+栈+env,命令行参数
进程状态 '进程上下文:context(PC,reg,堆栈指针等)
进程模式 :
用户模式 :空间地址0x0000 0000 -0xbfff ffff 3G空间,资源访问受限。
内核模式 :空间地址0xC000 0000 -0xffff ffff 1G共享空间。
cpu 进程切换与模式切换
进程切换:进程交替执行,时间片结束或进程让出cpu(sleep_on()sleep_on_interruptible())-->进程进入睡眠态(Task_Un/interrupt)
 模式切换: cpu执行不同功能代码时,进行模式切换,表现为寄存器使用变化.

进程状态图:其中D态是不可中断的睡眠态,S态可以中断的睡眠态。


进程命令
kill  -l 查看kill的有那些信号, kill  signal PID 命令是对某进程进行相应的处理。 
 nice+renice
 priority PRI内核调整值。
nice     用户可调值
PRI(new) = PRI(old) + nice(-20~19)
nice设置一个将要运行的程序的优先级 .例如; nice -n 5  vim ,ps -l
renice调整一个正在运行进程的优先级 。例如:renice 10 pid

二.进程api
1.fork():父进程返回子进程的id号,子进程返回0. (每次调用fork()函数时,它都会生成一个子进程副本,副本代码和父进程一样,子进程没有执行fork()函数,而是从fork()函数调用的下一条语句开始执行代码操作的
父子进程执行先后顺序不确定.。子进程继承了父进程的属性(打开的文件,所在目录,所在的组,uid,关联终端);
vfork()函数:先保证子进程运行,同时与父进程共享进程的4G空间。如果数据 发生了改变,父进程运行时会在改变的基础上去进行操作。(注:我们在调用这个函数的时候要exit()函数去结束子进程防止出现段错误)


应用:当我们在写程序的时候如果想同时运行两个不同功能时,我们可以用fork函数来创建子进程来运行
getpid():获取当前的进程号:


2.exit() 和 _exit()函数:
exit() 和 _exit()函数都是用来终止进程的,只是exit()函数在终止进程的时候它把进程的缓存区给清理了,让缓存区中的东西刷入到你原本的文件里去,而_exit()函数是直接调用系统调用去结束这个进程,并没有把缓存区的东西给刷出去,清除其使用的内存空间,并销毁其在内核中的各种数据结构。(若要保证数据的完整性,最好使用exit()函数)


3.wait()和waitpid()函数:
wait函数:在使用这个函数,会使进程阻塞,直到任意一个子进程结束或者是该进程接收到一个信号为止。如果该进程没有子进程或者其子进程已经结束,wait函数会立即返回-1。 具体用法看书本。
我们在使用fork()函数的时候要调用wait函数来回收它的子进程,防止他的子进程成为一个孤儿进程
status的值是exit()里面的值,
在调用waitpid()时,status的值会随着你的终止进程的方式改变而改变的,
如果你是正常结束这个进程的,它的值就是exit()里面的值,值会存在第二个字节上,第一个字节为0;
如果你是用信号结束这个进程的话,它的值是这个信号的值,并放在第一个字节上,第二个字节为0;
宏的方式判断是正常结束还是信号结束:




4.exec函数族:
exec函数族的作用:当我们想在这个子进程中去运行新的程序的时候,我们可以调用这个函数,去运行新的程序,把之前的虚拟内存的东西换成我们现在这个新的东西,之前的东西就会释放掉,但他的进程号我们还在使用。(原来之前后面的代码也不在运行了)
exec函数族 : execl()函数原型:execl(路径名,你要操作的命令,NULL),这个函数是以列表的形式写的
execv函数:这个是吧列表换成了一个指针数组, execlp和execvp函数;这个就是不用去写路径名,直接写个可执行文件就行,但是这个可执行文件必须在库文件里,否者无法运行,重点:每个写的时候须NULL结束
execve() 和 execle()函数,就是其后面加了一个环境变量。

5.守护进程:
守护进程常常在系统启动时开始运行,在系统关闭时终止,它是一个后台服务进程,通常独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事情。
守护进程编写的步骤:1.创建子进程,退出父进程。2.在子进程中创建新会话。3.改变当前目录为根目录。
4.重设文件权限掩码。5.关闭文件描述符。(这样让着进程完全脱离当前的终端,不受当前终端的控制)
一个会话又可以包含多个进程组。一个会话对应一个控制终端。
创建会话组:setsid(), 改变当前目录:chdir("/temp")  重设文件权限掩码:umask(0).
关闭文件描述符:getdtablesize();
1.进程组:
        Shell上的一条命令行形成一个进程组 
        每个进程必定属于一个进程组,也只能属于一个进程组。
        组中领头进程为进程组长,pgid==组长id
        组长可退出
        组一直存在到最后一个进程退出或加入了其他组。
        getpgid() 获取组id
        setpgid(0,0) 加入或创建组
    2.会话:
        一个会话又可以包含多个进程组.
        一个会话对应一个控制终端.
        登陆一次终端就会产生一个会话session
        分为前台进程组(only one )和后台进程组
        setsid();
        可建立一个新的会话;如果调用该函数的进程不是进程组的领头进程, 该函数才能建立新的会话. 
        调用setsid()之后, 调用进程将成为新会话的领头进程. 

守护进程出错问题:
可以使用函数,把错误信息写到系统给的文件里,
函数有:openlog():打开系统日志服务的连接,
syslog():向系统日志文件写入消息(出错的原因) 。closelog():关闭系统日志服务连接。