简介:这节、我们将讲解进程控制有关的概念。我们将介绍进程标识符、进程创建、回收,还有一些进程有关的函数。
1:首先、我们先介绍进程有关的概念。
a:进程标识符:我们这里所说的进程标识符就是进程ID,前面我们曾介绍进程有效用户ID和有效组ID。在这将详细讲解一下进程ID有关的内容。
1>:第一点:在一台机器上,每个进程有唯一的一个进程ID,它被用来区分不同的进程。我们通常成为该进程ID成为进程标识符,我们可以使用如下函数获取
pid_t getpid();
此函数返回调用进程的进程ID,同时需要注意一点的是,进程ID使用pid_t结构存储。(在Linux中以_t结尾的关键字通常是使用typedef重定义的类型。
在这里我们需要介绍一下有关进程ID号,在Linux中有许多后台进程在执行,通常进程ID为0的进程是初始化的进程。还有一些其他的进程、我们在这里就不一一介绍了。
我们还可以使用如下进程获取父进程的ID,
pid_t getppid();
此函数返回调用进程的父进程ID。
接下来我们介绍一下进程有效用户ID和有效组ID以及进程实际用户ID和实际组ID:通常情况下、进程有效ID和实际ID就是调用进程用户的实际ID,但是呢,如果我们将该程序文件设置
了上一节介绍的关键字,那么进程的有效用户ID就是该程序文件有效ID。进程的有效ID决定了进程访问文件的权限。
就像passwd文件,它就设置了那个关键字,然我们每个用户都可以更改用户密码。
接下来、我们介绍如何更改进程有关的ID函数。首先、我们介绍如何更改进程的有效用户ID。
int seteuid(uid_t uid);
int setegid(gid_t gid);
这两个函数是设置用户的有效用户ID和实际用户ID位,但是还是有一些设置条件限制的。当程序是超级用户的时候,程序可以将有效用户ID设置位参数uid。如果程序不是超级用户的时候,仅可以将有效用户ID设置为程序的实际用户ID或者保存设置的用户ID。其它情况设置不了,将出现错误。
int setuid(uid_t uid);
int setgid(gid_t gid);
此函数和上面那个函数有一些相似,但是它可以更改所有ID位。当执行进程有超级用户权限的时候,它可以将实际ID、有效ID、保存设置的ID都设置成参数的id。如果没有特权、那么跟上述的结果一样。其他情况将失败。
int setreuid(uid_t ruid, uid_t euid);
int setregid(gid_t rgid, gid_t egid):
如果非特权用户使用此函数,那么将交换实际用户ID和有效用户ID。如果是超级用户,那么将实际用户ID和有效用户ID设置为参数对应的ID(如果对应的参数是-1,那么将保持对应的ID不变)。
![file](//img1.sycdn.imooc.com/601622fd0001df9908100612.png)
2:接下来,我们讲解进程有关的标识符和一些进程有关的函数。
每个进程都有一个非负整数标识唯一的进程ID。这个ID对于一个系统来说、这个数值是唯一确定的。
a:进程的创建。
pid_t fork();//此函数用于创建进程它的返回值是创建进程的ID。但是呢这个函数时被调用一次、但是这个函数返回两次,在父进程中它返回创建子进程的ID、在子进程中它返回0.
子进程和父进程继续执行fork之后的命令。子进程是父进程的副本(父子进程只是共享正文段),并且对于像堆、栈等都是写时复制、读时共享。但是这里注意一点的是,子进程和父进程
执行的顺序是不确定的。当然子进程也会继承父进程许多内容,就像父进程打开的文件描述符、子进程的继承情况如下图所示。
同时、进程还继承和如下资源。
同时、fork函数还可能执行失败。每个实际ID的用户都有进程数目的限制,当我们超过这一个限制将无法创建新的进程。
pid_t vfork();
同样vfork函数也会创建一个进程。但是不同的是、它不会有fork函数那些动作。它只会在父进程的地址空间中运行、当vfork创建出的进程退出之后,父进程才继续运行。并且、使用
该函数目的就是为了exec一个新的程序。
wait函数和waitpid函数:这两个函数用于回收子进程的。
当我们的子进程终止的时,内核会向父进程发送一个SIGCHLD信号,因为子进程终止是异步事件,所以发送信号进程通知。父进程可以选择忽略或者调用一个特殊的函数。
函数原型:
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int ptions);
statloc:此参数用于记录返回状态。
1. WIFEXITED(status) 为非0 → 进程正常结束
WEXITSTATUS(status) 如上宏为真,使用此宏 → 获取进程退出状态 (exit的参数)
2. WIFSIGNALED(status) 为非0 → 进程异常终止
WTERMSIG(status) 如上宏为真,使用此宏 → 取得使进程终止的那个信号的编号。
3. WIFSTOPPED(status) 为非0 → 进程处于暂停状态
WSTOPSIG(status) 如上宏为真,使用此宏 → 取得使进程暂停的那个信号的编号。
WIFCONTINUED(status) 为真 → 进程暂停后已经继续运行
pid
从参数的名字pid和类型pid_t中就可以看出,这里需要的是一个进程ID。但当pid取不同的值时,在这里有不同的意义。
pid>0时,只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。
pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。
pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。
options提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED两个选项,这是两个常数,可以用”|”运算符把它们连接起来使用
WNOHANG: 如果没有任何已经结束的子进程则马上返回,不予以等待。
WUNTRACED :如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会.
WCONTINUED:这个宏的意思我不太明白。
int waitid(idtype_t idtype, id_t id, siginfo_t *iinfop, int options);
与waitpid相似,waitid函数润许一个进程指定要等待的子进程。但是它使用单独的参数标识要等待的子进程类型。
idtype就是要等待子进程的类型:
P_PID:等待一个特定的子进程,id参数就是要等待的子进程。
P_PGID:等待一个进程组中任一子进程,id是进程组id。
P_ALL:等待任意子进程。
options:
WCONTINUED:等待一个进程,它以前曾被暂停,但又继续,并且状态并未报告。
WEXITED:等待已退出的进程。
WNOHANG:如果没有可用的子进程退出状态,立刻返回而阻塞。
WNOWAIT:不破坏子进程的状态,该子进程退出状态可有前面的函数调用取得。
WSTOPPED:等待一个子进程,它已经暂停,但其状态尚未报告。
infop:
这个关键字包含有关进程状态改变的生成信号的详细信息。
pid_t wait3(int *statloc, int optinos, struct rusage *rusage);
pid_t wait4(pid_t pid, int *statloc, int options, struct rusage *rusage);
这两个函数就不在此多做介绍了。
3:最后、我们讲解进程有关的一些函数。
int system(const char* cmdstring);
此函数用于执行cmdstring字符串对应的命令,当cmdstring字符串对应的是空的情况下、当system程序可以用的时候,返回一个非0值。
FILE* popen(const char* command, const char* type);
此函数执行command并且返回FILE文件描述符指针,其中type是对文件描述符读或者写。
int pclose(FILE *stream);
使用这个函数关闭前面返回的文件描述符,