专题 8 进程控制

来源:互联网 发布:有没有发型设计软件 编辑:程序博客网 时间:2024/06/06 02:18
  1. 进程的标识、命令行与环境变量

/****************************/

#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]));

}

}

  1. 进程的生命周期

    1. 进程的创建

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;

}

    1. 新程序的执行

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);

    1. 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;

}

    1. vfork-exec模型和system模型

pid_tvfork();

函数vforkfork在功能和调用形式上类似,也能创建子进程,但二者有如下区别:

  1. vfork创建的子进程并不复制父进程的数据,在随后的exec调用中系统会复制新进程的数据到内存中,继而避免了一次数据复制过程。

  2. 父进程以vfork方式创建子进程后将被阻塞,直到子进程退出或执行exec调用才继续运行。

当子进程只是用来创建新程序时,vfork-exec模型比fork-exec模型具有更高的效率,这种方法也是shell创建新进程的方式。

int system(char *string);

函数system阻塞调用它的进程,并执行字符串string中的shell命令,它可以理解为vfork-exec模型的简易表达方式,如下所示:

/********systemvfork描述****************/

if(vfork()== 0)

{

execl(“/bin/sh”,“-C’, string, 0);

exit(0);

}

    1. 进程的休眠与终止

void exit(int status);

参数status的低8位记载了进程的终止状态,进程终止后将这个状态返回给它的父进程。

    1. 进程的同步

pid_t wait(int *status);

pid_t waitpid(pid_t pid, int *status, int options);

函数wait挂起调用它的进程,直到它的任一子进程退出或者收到一个不能忽略的信号为止,如果在父进程执行wait调用前就已经有子进程退出,则立即返回。函数调用成功后返回结束运行子进程的ID,否则返回-1

wait函数参数status取舍情况表

子进程终止原因

Status8

Status8

调用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;

}

  1. 守护进程

守护进程(daemon)是生存期长的一种进程。它们常常在系统引导装入时启动,在系统关闭时终止。因为它们没有控制终端,所以说它们是在后台进程的。所有守护进程都以超级用户优先级运行。所有守护进程的父进程都init进程。守护进程一般是进程组的首进程。

查看守护进程命令:

ps –ef

创建守护进程的步骤:

  1. 创建子进程, 父进程退出。

保证子进程不是一个进程组的首进程,是调用setsid调用的必要的前提条件。

  1. 调用setsid以创建一个新的会话,并担任该会话组的组长。调用setsid作用有三:

    1. 成为新的会话组(一个或多个进程组)的首进程。

    2. 成为一个新进程组的首进程。

    3. 脱离控制终端。

  2. 改变当前目录为根目录

chdir(“/”);

  1. 重设文件权限掩码

unmask(0);表示打开所有文件权限

  1. 关闭不再需要的文件描述符


#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);

}

}




原创粉丝点击