Ubuntu下UnixC的第八天

回忆昨天内容
一、进程的基础
进程树 树根 init进程 1号进程

父子关系 兄弟关系
pid PCB
进程是资源分配的基本单位

ps -aux|grep 进程数 
top
pstree

二、创建子进程
fork(2)
父进程和子进程是异步的
wait(2)让父进程和子进程同步
复制父进程的PCB
PCB中有文件描述符  进程的映像

父进程调用fork(2) 但是返回时 已经是两个进程了
调用fork的进程是父进程
新的进程是子进程
三、进程的终止
1、return和exit(3)
status&0377 传递给父进程
2、遗言函数的注册 atexit(3)on_exit(3)
四、回收子进程的资源
    wait(2)家族
    wait
    僵尸进程zombie
    孤儿进程orphan
今天的内容:
一、waitpid(2)
      #include <sys/types.h>
       #include <sys/wait.h>

     
    wait(&status)=waitpid(-1,&status,0)  

       pid_t waitpid(pid_t pid, int *status, int options);
    功能:等待回收子进程的资源
    参数:  pid指定一个特定的孩子
        <-1   pid的绝对值是一个进程组的pid,等待
        -1  等待任意子进程
        0  等待跟父进程同组的子进程的终止
        >0  等待的子进程的pid
        status将子进程的退出状态保存在这个变量指向的空间里
        options
            WNOHANG  如果没有子进程的终止,立即返回
            0   阻塞等待子进程的终止
    返回值:成功 返回子进程的pid(收到了)   如果设置了非阻塞,未收到的情况下 返回0
        错误 -1  errno被设置
    
    process group
    进程组    进程组有多个进程,但是有一个组长    进程组的pid就是组长这个进程的pid
    fork产生的子进程默认是同一组
    
    代码验证 waitpid.c
二、进程映像的替换
    fork(2)创建子进程后,子进程继承父进程的映像
    PCB fd image
    exec(3)家族
    execve(2)
       #include <unistd.h>

       int execve(const char *filename, char *const argv[],
                  char *const envp[]);
    功能:进程映像的替换
    参数:filename 可执行程序,使用这个可执行程序替换掉从父进程继承的image
        argv作为新程序的参数传递
        envp作为新映像的环境变量传递    都必须以NULL结尾
    返回值:成功  不返回
        失败 -1 errno被设置
    
      #include <unistd.h>

       extern char **environ;

       int execl(const char *path, const char *arg, ...
                       /* (char  *) NULL */);
       int execlp(const char *file, const char *arg, ...
                       /* (char  *) NULL */);
       int execle(const char *path, const char *arg, ...
                       /*, (char *) NULL, char * const envp[] */);
       int execv(const char *path, char *const argv[]);
       int execvp(const char *file, char *const argv[]);
       int execvpe(const char *file, char *const argv[],
                       char *const envp[]);
    l list argv[] argv[]
    v vector
    p PATH 带这个字符的,指示找可执行程序时,到PATH指定的路径下找
    e 不带这个字符的,默认从父进程继承环境变量
        带这个字符的,用户指定环境变量,传递给新的映像
    举例说明 创建一个子进程 将子进程的映像替换 代码参见 execl.c
    bash如何执行a.out
    bash fork execl("./a.out","a.out",NULL);
        wait
    bash ls
    ls 和bash是两个独立的可执行程序。执行时和bash 一个父进程,一个子进程(是两个进程)
    这种命令称为bash的外部命令,不是bash本身携带的
    本身为bash的一部分的命令,执行时,不需要fork创建子进程,这些命令称为bash的内部命令

    如何判断一个命令是内部命令还是外部命令?
    type command
三、环境变量
环境变量是进程的环境变量
externa char** environ; 指向环境变量列表的首地址
char * envp[] ; envp是常量
    编写程序遍历进程的环境变量列表
    代码参见 t_env.c
    默认的情况是将父进程的环境变量传递给新的程序
    代码参见 t_env1.c
    
    使用程序操作环境变量
获取环境变量的值
getenv(3)
     #include <stdlib.h>

       char *getenv(const char *name);


    功能:找到环境变量的值
    参数:
    name 指定要找的环境变量的名字
    返回值: 找不到 NULL
        找到 返回value string的地址
设置环境变量的值
setenv(3)
    #include <stdlib.h>

       int setenv(const char *name, const char *value, int overwrite);
    功能:改变或者增加一个环境变量    如果环境变量名字不存在,增加一个环境变量
    参数 name指定了环境变量的名字
         value 环境变量的值
         overwrite 非0 如果环境变量存在,将环境变量的值改为value
            0  如果环境变量存在,环境变量不改变
    返回值:
          成功 0
        失败 -1 errno被设置
删除环境变量
unsetenv(3)
     #include <stdlib.h>
       int unsetenv(const char *name);
    功能:删除环境变量
    参数: name指定环境变量的名字
    返回值:成功返回0
        失败返回-1 errno被设置
清除所有环境变量
clearenv(3)
     #include <stdlib.h>

       int clearenv(void);
    功能:清除所有的环境变量   设置全局变量environ为NULL
    参数:无
    返回值:成功 0
        失败 非0

    putenv(3)
    代码参见 env_os.c
    
    传递带环境变量的参数exece.c
四、管道   进程间的通讯
无名管道
ps -aux|grep a.out
应用与具有亲缘关系的进程间通讯   父子关系  兄弟关系
  #include <unistd.h>

       int pipe(int pipefd[2]);
功能:创建一个管道    一个用于进程间通信的单向数据管道 单工
参数:
pipefd[2]  返回管道两端的文件描述符  
    pipefd[0]指向管道读端    
    pipefd[1]指向管道写端
返回值:  成功返回0  错误返回-1 errno被设置    //09pm178分
1、创建管道,返回两个文件描述符
2、创建子进程,子进程继承父进程的文件描述符
3、子进程负责的任务(读
    关闭写端
        从管道读取数据(阻塞,无数据时等待)
        读取到数据以后,将数据输出到显示器
        close(读端)
        子进程终止
4、父进程负责的任务(写
    关闭读端
        将数据写入到管道(阻塞,满则等待)
        close(写端)
        回收子进程的资源
        
    代码参见pipe.c
有名管道


env_os.c

 

#include<stdio.h>
#include<stdlib.h>

int main(void){
#if 0
    //获取环境变量的值
    char *str=getenv("caption");
    if(!str)
        printf("not found...\n");
    else
    printf("%s\n",str);
#endif
    //增加一个环境变量
    setenv("caption","beijing",0);
    char *str=getenv("caption");
    if(!str)
        printf("not found...\n");
    else
    printf("%s\n",str);
    return 0;
}
 

exece.c

 

#include<t_stdio.h>
#include<stdlib.h>
#include<t_file.h>
#include<sys/wait.h>

int main(){
    //创建子进程
        char *ps_envp[]={"caption=beijing","user=nan","name=zhangsan",NULL};
    pid_t pid=fork();
    if(pid==-1) E_MSG("fork",-1);
    if(pid==0){
    //    execlp("ps","ps","-o","pid,ppid,pgrp,comm",NULL);
        //以下两句只有失败时才能够执行
    //    execl("./t_env","t_env",NULL);
        execle("./t_env","t_env",NULL,ps_envp);
    //    execlp("/bin/ps","ps","-o","pid,ppid,pgrp,comm",NULL);
        perror("execl");
        exit(-1);
    }else{
        wait(NULL);//等待子进程结束
    }
    return 0;
}
 

execl.c

  #include<t_stdio.h>
#include<stdlib.h>
#include<t_file.h>
#include<sys/wait.h>
int main(){
    //创建子进程
        char *ps_argv[]={"ps","-o","pid,ppid,pgrp,comm",NULL};
    pid_t pid=fork();
    if(pid==-1) E_MSG("fork",-1);
    if(pid==0){
    //    execlp("ps","ps","-o","pid,ppid,pgrp,comm",NULL);
        //以下两句只有失败时才能够执行
        execvp("ps",ps_argv);
    //    execlp("/bin/ps","ps","-o","pid,ppid,pgrp,comm",NULL);
        perror("execl");
        exit(-1);
    }else{
        wait(NULL);//等待子进程结束
    }
    return 0;
}

pipe.c

 

#include<t_stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
int main(){
    int fd[2];
    char buf[128];
    char* msg="this is a test..\n";
    //在父进程创建管道,fd[0]指向管道的读端,fd[1]指向管道的写端
    int pp=pipe(fd);
    if(pp==-1) E_MSG("pipe",-1);
    //创建子进程,子进程继承父进程的文件描述符。
    pid_t pid=fork();
    if(pid==-1) E_MSG("fork",-1);
    if(pid==0){
    //这是子进程负责的任务
        close(fd[1]);
        int r=read(fd[0],buf,128);
        write(1,buf,r);
        close(fd[0]);
        exit(0);
    }else{//这是父进程负责的任务
        close(fd[0]);
        sleep(5);
        write(fd[1],msg,strlen(msg));
        close(fd[1]);
        wait(NULL);

    }
    return 0;
}
 

t_env.c

#include<stdio.h>
#include<unistd.h>
extern char** environ;
int main(void){
    int i;
    for(i=0;environ[i]!=NULL;i++)
                printf("%s\n",environ[i]);
    return 0;
}
 

waitpid.c

#include<t_stdio.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<t_file.h>
int main(){
    //创建 子进程
    int s;
    pid_t pid=fork();
    if(pid==-1)E_MSG("fork",-1);
    if(pid==0){//子进程执行的
        printf("child process...%d\n",getpid());
        sleep(10);
        exit(-1);
    }
    else {
    //父进程执行的
    int w=waitpid(0,&s,0);//挂起执行,等待子进程终止
        if(w>0){
    printf("parent process...\n");
        if(WIFEXITED(s))//子进程正常终止
          //输出子进程终止状态码
            printf("exit code:%d\n",WEXITSTATUS(s));
        if(WIFSIGNALED(s))//子进程被信号打断
    //输出打断子进程的信号编号
          printf("signum...%d\n",WTERMSIG(s));
        }
    }
    return 0;
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值