进程的标识、命令行与环境变量
/****************************/
#include<unistd.h>
intmain()
{
printf(“pid= [%d], gid = [%d], ppid=[%d]\n”, getpid(), getpgrp(), getppid());
printf(“uid=[%d],euid=[%d], gid=[%d], egid=[%d]\n”, getuid(), geteuid(), getgid(),getegid());
return0;
}
/*****************打印全部环境变量******************/
#include<stdio.h>
extern char **environ;
intmain()
{
char**p = environ;
while(*p)
{
fprintf(stderr,“%s\n”, *p);
p++;
}
}
/***************读取特定变量*********************/
#include<stdlib.h>
intmain()
{
inti;
for(i= 1; i < argc; i++)
{
fprintf(stderr,“%s=%s\n”, argv[i], getenv(argv[i]));
}
}
进程的生命周期
进程的创建
pid_tfork();
/************创建子进程****************/
#include<unistd.h>
#include<stdio.h>
intmain()
{
pid_t pid;
int i;
fprintf(stderr,“Process Begin, pid=[%d], i=[%d]\n”, getpid(), i);
if((pid=fork())> 0)
{
fprintf(stderr,“parent pid=[%d], child pid=[%d]\n”, getpid(), pid);
}
elseif(pid == 0)
{
fprintf(stderr,“Child pid=[%d]\n”, getpid());
i++;
}
else
fprintf(stderr,“Fork failed.\n”);
fprintf(stderr,“Process end. pid=[%d], i=[%d]\n”, getpid(), i);
return0;
}
新程序的执行
exec函数族原型:
int execl(const char *path, const char *arg0, …, (char*)0);
int execle(const char *path, const char *arg0, …, (char *)0, char*const envp[]);
int execlp(const char *file, const char *arg0, …, (char *)0);
int execv(const char *path, const char *argv[]);
int execve(const char *path, const char *argv[], const char *argvp[]);
int execvp(const char *file, const char *argv[]);
externchar **environ;
命名规律:字母l表示变长命令行参数;字母v表示函数采用指针数组命令行参数;字母p表示函数采用PATH变量查找程序;字母e表示函数使用envp显示传递环境变量。
实例:
如何通过exec函数族执行程序”ls–l /u”?
ANS:
externchar **environ;
char*argv[] = {“-l”, “/u”, 0};
execl(“/bin/ls”,“-l”, “/u”, 0);
execlp(“ls”,“-l”, “/u”, 0);
execv(“/bin/ls”,argv);
execve(“/bin/ls”,argv, environ);
execvp(“ls”,argv);
fork-exec模型
/*****fork-exec调用模型*********/
#include<unistd.h>
#include<stdio.h>
intmain()
{
pid_t pid;
if((pid= fork()) == 0) /*子进程*/
{
fprintf(stderr,“—begin--\n”);
execl(“/bin/ls”,“-l”, “/u”, 0);
fprintf(stderr,“—end--\n”);
}
elseif(pid > 0) /*父进程*/
{
fprintf(stderr,“fork child pid=[%d]\n”, pid);
}
else
fprintf(stderr,“fork failed. \n”);
return0;
}
vfork-exec模型和system模型
pid_tvfork();
函数vfork与fork在功能和调用形式上类似,也能创建子进程,但二者有如下区别:
vfork创建的子进程并不复制父进程的数据,在随后的exec调用中系统会复制新进程的数据到内存中,继而避免了一次数据复制过程。
父进程以vfork方式创建子进程后将被阻塞,直到子进程退出或执行exec调用才继续运行。
当子进程只是用来创建新程序时,vfork-exec模型比fork-exec模型具有更高的效率,这种方法也是shell创建新进程的方式。
int system(char *string);
函数system阻塞调用它的进程,并执行字符串string中的shell命令,它可以理解为vfork-exec模型的简易表达方式,如下所示:
/********system的vfork描述****************/
if(vfork()== 0)
{
execl(“/bin/sh”,“-C’, string, 0);
exit(0);
}
进程的休眠与终止
void exit(int status);
参数status的低8位记载了进程的终止状态,进程终止后将这个状态返回给它的父进程。
进程的同步
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
函数wait挂起调用它的进程,直到它的任一子进程退出或者收到一个不能忽略的信号为止,如果在父进程执行wait调用前就已经有子进程退出,则立即返回。函数调用成功后返回结束运行子进程的ID,否则返回-1。
wait函数参数status取舍情况表
子进程终止原因 |
Status低8位 |
Status高8位 |
调用exit退出 |
0 |
exit的参数值的低8位 |
收到信号退出 |
引起终止的信号 |
0 |
函数waitpid可用于多个子进程的操作中。
waitpid参数pid的取值情况表
参数值 |
函数waitpid功能 |
pid>0 |
等等进程标识为pid的子进程结束 |
Pid=0 |
等待进程组标识等于父进程组的子进程结束 |
pid=-1 |
等待任意子进程结束 |
Pid<-1 |
等待进程组标识等于pid的绝对值子进程结束 |
waitpid参数options的聚会情况表
参数值 |
函数waitpid功能 |
WNOHANG |
非阻塞调用waitpid,当没有符合条件的子进程结束时函数立即返回 |
WUNTRACED |
如果在父进程执行waitpid调用前就已经有子进程退出,也立即返回 |
/***********wait调用模型**************/
#include<unistd.h>
int main()
{
pid_t i, j;
int status;
if((i= fork()) == 0)
{
fprintf(stderr,“child begin. pid=[%d]\n”, getpid());
sleep(40);
fprintf(stderr,“child end. pid=[%d]\n”, getpid());
exit(10);
}
j= wait(&status);
fprintf(stderr,“child pid=[%d], exit pid[%d], status[%d]\n”, i, j, status);
return 0;
}
守护进程
守护进程(daemon)是生存期长的一种进程。它们常常在系统引导装入时启动,在系统关闭时终止。因为它们没有控制终端,所以说它们是在后台进程的。所有守护进程都以超级用户优先级运行。所有守护进程的父进程都init进程。守护进程一般是进程组的首进程。
查看守护进程命令:
ps –ef
创建守护进程的步骤:
创建子进程, 父进程退出。
保证子进程不是一个进程组的首进程,是调用setsid调用的必要的前提条件。
调用setsid以创建一个新的会话,并担任该会话组的组长。调用setsid作用有三:
成为新的会话组(一个或多个进程组)的首进程。
成为一个新进程组的首进程。
脱离控制终端。
改变当前目录为根目录
chdir(“/”);
重设文件权限掩码
unmask(0);表示打开所有文件权限
关闭不再需要的文件描述符
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#define MAXFILE 65535
intmain()
{
pid_tpc;
inti, fd, len;
char*buf = "This is a Dameon\n";
len =strlen(buf);
pc =fork();
if(pc< 0)
{
printf("errorfork\n");
exit(1);
}
elseif(pc > 0)
{
exit(0);
}
setsid();
chdir("/");
umask(0);
for(i= 0; i < MAXFILE; i++)
close(i);
while(1)
{
if((fd= open("/tmp/dameon.log", O_CREAT | O_WRONLY | O_APPEND,0600)) < 0)
{
perror("open");
exit(1);
}
write(fd,buf, len+1);
close(fd);
sleep(5);
}
}