Chinaunix首页 | 论坛 | 博客
  • 博客访问: 108577
  • 博文数量: 45
  • 博客积分: 1810
  • 博客等级: 上尉
  • 技术积分: 345
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-03 21:57
文章分类
文章存档

2010年(26)

2009年(19)

我的朋友

分类: C/C++

2009-11-06 22:43:50

进程控制(笔记)
(说明:这些只是自己学习中针对自己的学习状况记录的一些笔记,并不是全面的介绍,其中结构很乱,可能只有我自己能看懂,这不是学习进程的专业教材,只是针对我个人的一些笔记,里面多有错误和不全面的地方,敬请与原谅)
进程的概念

进程的内存映像
进程的各种操作
守护进程的创建

linux 多用户 : 多个用户可以在同一时间使用计算机,多任务是linux可以同时执行几个任务,可以在一个任务没有执行完的时候执行其他任务

用fork创建一个新的进程。

fork() 创建一个新的进程,返回两个值。
fork() 函数的简介: 单单看书上的介绍还是不能深入理解函数的意义和具体的用法,只有在自己真正的有函数编了几个程序的时候才慢慢明白:
    :父进程调用fork来创建子进程,创建成功(注意是子进程创建成功后会返回两个值,0 和一个非零的正值,这两个值是描述当前进程执行的值,0 代表执行的是刚刚创建的子进程,非零值表示的是创建子进程的进程号,但现在正在执行的却是父进程。假如fork函数执行失败,会直接返回 -1 ,表示创建进程失败,也就不存在在返回第二个值了。即执行的返回值有 -1 和非负值之分,非负值值又有零值与非零值之分。
      在具体程序使用的过程中有 pid = fork() ;
     pid 是不会代表父进程的进程号的,之前犯过认为pid 的两个返回值一子进程的进程号另一个代表父进程进程号的错误。
用fork创建一个子进程后,子进程会创建一个新的存储空间来存放从父进程那里复制过来的所有资源,这是就会有一个问题,就是自己能成是完全复制父进程的资源,这是加入缓冲区里有东西的话,它也会一块复制,这样就造成了在fork一个新的函数之后,一些原本在fork之前的语句也要执行一遍,例如:
#include<.....
int main()
{
......
printf("hello world ") ;
pid = fork() ;

......
}
 这段代码在执行的时候 printf("hello world ") ; 会执行两遍,因为在执行这句的时候,输入的信息会现在放在缓存中 ,此时在用fork创建子进程会联通缓存中的数据一块复制到为自己开辟的空间里,所以在子进程运行的时候也会打印一遍 hello world ,还有应该看到此时printf语句中并没有 \n ,因为 \n 会将强制将数据从缓存中写入文件中,这样的话子进程复制父进程自于资源的时候就不会将改行数据复制到自己的存储空间中。
   

进程和程序是有区别的,进程是动态的,程序是静态的,进程是运行中的程序,程序只是一些保存在硬盘上的一些可执行代码。
进程内部又可分为许都线程,线程是比进程更小的能独立运行的几本单元,线程不分配系统资源,它和其它线程一块分享此进程所有的全部资源。一个线程可以创建一个或撤销一个其他的线程,同一个线程中可以有多个线程并行执行。

每一个进程都有自己的ID,这些都可以通过相应的函数来取得
pid_t getpid() 取得当前进程的进程的 ID
pid_t getppid() 取得当前进程的父进程的 ID        
pid_t getuid() 取得当前进程实际用户 ID
pid_t geteuid() 取得当前进程的有效用户ID
pid_t gergid() 获得进程的实际组ID
pid_t getegid() 获得进程的有效用户组ID

实际用户ID: 就是实际创建此进程的用户ID 不管此用户以何身份创建此进程;区分于有效用户ID ;
有效用户ID : 表示此进程是以什么用户身份惊醒创建的,假如此进程 由用户 A 以普通用户的身份来创建,那么此进程的实际用户 ID 和有效用户ID都是用户A的 ID ,如果此进程是用户A以root的身份创建的,那么,这个进程的实际用户ID是用户 A 的ID,而有效用户ID是root的ID 。
组ID : 就是实际(有效)用户所属组的ID,实际组和有效用户组的含义同实际用户和有效用户。

进程的结构:一个进程由3部分组成: 代码段,数据段,堆栈断。
 代码断就是存放程序的可执行代码的地方,数据断就是存档程序的全局变量,常量,静态变量的地方;堆栈段:堆用于存放动态分配的变量,栈用于存放函数的参数么函数的内部定义的局部变量。
  
exec 函数的使用 :
一个进程可以调用exec 来执行一个可执行程序,当调用exec 之后,会执行一个新的程序,原程序就死亡了,将他原有的进程号传给新的程序,同时原有的进程的代码段,数据段,堆栈断都被废除,为新的程序分配新的 这些段。 注意:进程号还是原来进程的。
linux 下exec 家族的 六种不同的调用形式: 头文件都在 unistd.h 里面
int execve(const char *path ,char *const argc,char *const envp[] )    path 是要执行的命令的路径,argc 和argv 于 main函数的 argc 和 argv 对应。
int execv (const char *path ,char *const envp[] )
int execle(......)
int execl (......)
int exevp(.....)
int execlp (......)
这些都可以 有man查到。
环境变量: 包括用户的主目录、终端类型、当前目录等。
一般不会有返回值,如果有一个错误的事件,返回:-1
 errno         错误描述
EACCES      执向的文件或脚本文件没有可执行位。
E2BIG        新程序的命令行参数与环境变量容量之和超过了ARG_MAX
ENOEXEC     由于没有正确的文件格式,指定的文件无法正确的执行
ENOMEM         由于没有足够的内存空间来执行指定的程序
ETXTBUSY    指定的文件被一个或多个进程以可写的 打开
EIO        从文件系统中读入文件时发生I/O 错误

exec 当执行脚本时,文件的第一行必须以这样开头: #!interpertname [arg]
其中in... 是shell或其他的解释器,如 /bin/sh 或 /usr/bin/perl arg 是传递的参数


envion 是系统预定义的全局变量。 可以在程序中调用来显示各个环境变量的值。 它是一个双指针类型,可以理解为是一个特殊的数组。
extern **envion 在程序中声明它。
printf("%s",*envion); 来使用它。
int main() 的完整形式是( int argc,int *argv[],char *envion[])

等待进程结束含函数:
#include
#include

pid_t wait (int *starloc)

pid_t wait (pid_t pid ,int *statloc,int option)
sys/wait.h 中定义的进程退出状态的宏。
 WIFEXITED(stat_val)     进程正常结束,返回一个非零值,为真,若异常结束,返回0 为假。
 WEXITSTTUS         若 WET... 返回的非零,它返回子进程中的 exit _exit 参数低于8位。
WIFSIGNALED(stat_val)     若子进程异常终止,它就取得一个非零值,表示真。
WTERMSIG(stat_val) 如果宏WIFSIGNALED 的值为非零,该宏返回使子进程异常终止的信号编号。
WIFSTOPPED(stat_val) 若进程暂停,它就取得一个非零值,表示真。
WSTOPSIG(stat_val) 若 WIFSTOPPED 非零,它返回使子进程暂停的信号编号。
这些宏都可以在 man wait 时找到。
waitpid 是用来等待一个特殊进程(进程号是: pid )的结束,option 参数的意义:允许用户改变waitpid 的行为,若其被赋值为 WNOHANG 表示父进程不被挂起而立即返回并执行其后的代码。
程序片段理解:
int stat_val ;
pid_t child_pid;
child_pid = wait (&star_val);
....
if(WIFEXITED(star_val) )
    printf("Child exited with code %d ",    WEXITSTATUS(stat_val) ) ;
WEXITSTATUS 通过stat_val 来取得子进程的退出状态,即return 或 exit 所带的参数。这个必须是在WIFEXITED(stat_val) 返回为非零值时才有效,即表示子进程是正常结束的。(假如进程不是正常结束的,也不会有 return或exit 返回了)。
 
阅读(877) | 评论(0) | 转发(0) |
0

上一篇:终端不能正常启动

下一篇:宏的使用

给主人留下些什么吧!~~