IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Unix进程的学习 -> 正文阅读

[系统运维]Unix进程的学习

Unix进程的学习

一、初步了解父子进程的特性,特别是fork()函数的使用:

  • 调用一次,返回两次
  • 并发执行
  • 相同但是独立的地址空间
  • 共享文件

??示例程序如下所示:

#include "csapp.h"

int main(int argc, char** argv){
    pid_t pid;
    int x = 1;
    pid = Fork();
    if (pid == 0){
        /*子进程 */
        printf("child : x = %d\n", ++x);
        exit(0);
    }
    /*父进程*/
    printf("parent: x = %d\n", --x);
    exit(0);
    return 0;
}

??运行结果如下所示:

$$$ ./make.sh 1.fork.cpp
parent: x = 0
child : x = 2

??结果说明:

  1. perent对应的x为0,child对应的x为2。说明父子进程拥有相同但是独立的地址空间,每个继承拥有相同的用户栈、本地变量值、堆、全局变量值、代码,但是都是自己的私有地址空间。
  2. printf()的输出是在同一个终端。这个表示了共享文件的特性,子进程继承了父进程所有的打开文件,所以输出到同一终端

二、fork()的嵌套使用:

??示例程序如下所示:

#include "csapp.h"

int main(int argc, char** argv){
    pid_t pid1;
    pid_t pid2;
    pid1 = Fork();
    pid2 = Fork();
    printf("hello--->pid1 = %d--->pid2 = %d\n", pid1, pid2);
    return 0;
}

??运行结果如下所示:

$$$ ./make.sh 2.more_fork.c
hello--->pid1 = 4969--->pid2 = 4970
hello--->pid1 = 0--->pid2 = 4971
hello--->pid1 = 0--->pid2 = 0
hello--->pid1 = 4969--->pid2 = 0

??结果说明:

main
fork
pid1=4969
pid1=0
fork
pid2=4970
pid2=0
fork
pid2=4971
pid2=0
printf
printf
printf
printf

三、fork()的相关练习:

??预演如下所示代码父子进程的输出:

#include "csapp.h"

int main(int argc, char** argv){
    int x = 1;
    if (Fork() == 0){
        printf("p1:x=%d\n", ++x);
    }
    printf("p2:x=%d\n", --x);
    exit(0);
}

??本人想象结果如下:

# 父进程的输出
p2:x=0
# 子进程的输出
p1:x=2
p2:x=1

??运行结果如下所示:

$$$ ./make.sh 3.practise.c
p2:x=0
p1:x=2
p2:x=1

四、fork()的相关练习:

??预演如下所示代码所有可能的输出:

#include "csapp.h"

int main(int argc, char** argv){
    if(Fork() == 0){
        printf("a");
        fflush(stdout);
    }else{
        printf("b");
        fflush(stdout);
        waitpid(-1, NULL, 0);
    }
    printf("c");
    fflush(stdout);
    exit(0);
}

??本人想象结果如下:

# 父进程的输出
bc
# 子进程的输出
ac
# 因为waitpid的存在,所以父进程的c在子进程的c之后
bacc
abcc
acbc

??运行结果如下所示:

$$$ ./make.sh 4.practise.c
bacc

五、waitpid的示例:

??预演如下所示代码所有可能的输出:

#include "csapp.h"
#define N 20
#define MIN(a,b) ((a>b)?b:a)
int main(int argc, char** argv){
    int status, i;
    pid_t pid;
    //创建N个子进程
    for (i = 0; i < N; i++){
        if((pid = Fork()) == 0){
            srand(time(0));
            sleep(MIN(rand(), 4));
            exit(100+i);
        }
    }
    //不按照特定的顺序来回收子线程
    while((pid = waitpid(-1, &status, 0)) > 0){
        if (WIFEXITED(status)){
            printf("child %d terminated normally with exit status=%d\n", pid, WEXITSTATUS(status));
        }else{
            printf("child %d terminated abnormally\n", pid);
        }
    }
    if(errno != ECHILD){
        unix_error("waitpid error");
    }
    exit(0);
}

??运行结果如下所示:

$$$ ./make.sh 5.waitpid.c
child 13351 terminated normally with exit status=100
child 13352 terminated normally with exit status=101
child 13353 terminated normally with exit status=102
child 13354 terminated normally with exit status=103
child 13355 terminated normally with exit status=104
child 13356 terminated normally with exit status=105
child 13357 terminated normally with exit status=106
child 13358 terminated normally with exit status=107
child 13359 terminated normally with exit status=108
child 13361 terminated normally with exit status=110
child 13363 terminated normally with exit status=112
child 13364 terminated normally with exit status=113
child 13360 terminated normally with exit status=109
child 13365 terminated normally with exit status=114
child 13366 terminated normally with exit status=115
child 13367 terminated normally with exit status=116
child 13368 terminated normally with exit status=117
child 13369 terminated normally with exit status=118
child 13370 terminated normally with exit status=119
child 13362 terminated normally with exit status=111

六、waitpid同步等待的示例:

??预演如下所示代码所有可能的输出:

#include "csapp.h"
#define N 20
#define MIN(a,b) ((a>b)?b:a)
int main(int argc, char** argv){
    int status, i;
    pid_t pid[N], retpid;
    //创建N个子进程
    for (i = 0; i < N; i++){
        if((pid[i] = Fork()) == 0){
            srand(time(0));
            sleep(MIN(rand(), 4));
            exit(100+i);
        }
    }
    //按照特定的顺序来回收对应的子线程
    i = 0;
    while((retpid = waitpid(pid[i++], &status, 0)) > 0){
        if (WIFEXITED(status)){
            printf("child %d terminated normally with exit status=%d\n", retpid, WEXITSTATUS(status));
        }else{
            printf("child %d terminated abnormally\n", retpid);
        }
    }
    if(errno != ECHILD){
        unix_error("waitpid error");
    }
    exit(0);
}

??运行结果如下所示:

$$$ ./make.sh 6.waitpid_async.c
child 13789 terminated normally with exit status=100
child 13790 terminated normally with exit status=101
child 13791 terminated normally with exit status=102
child 13792 terminated normally with exit status=103
child 13793 terminated normally with exit status=104
child 13794 terminated normally with exit status=105
child 13795 terminated normally with exit status=106
child 13796 terminated normally with exit status=107
child 13797 terminated normally with exit status=108
child 13798 terminated normally with exit status=109
child 13799 terminated normally with exit status=110
child 13800 terminated normally with exit status=111
child 13801 terminated normally with exit status=112
child 13802 terminated normally with exit status=113
child 13803 terminated normally with exit status=114
child 13804 terminated normally with exit status=115
child 13805 terminated normally with exit status=116
child 13806 terminated normally with exit status=117
child 13807 terminated normally with exit status=118
child 13808 terminated normally with exit status=119

七、waitpid的相关练习:

??预演如下所示代码所有可能的输出:

#include "csapp.h"
#define N 20
#define MIN(a,b) ((a>b)?b:a)
int main(int argc, char** argv){
    int status;
    pid_t pid;
    printf("Hello\n");
    pid = Fork();
    printf("%d\n", !pid);
    if (pid != 0){
        if (waitpid(-1, &status, 0) > 0){
            if (WIFEXITED(status) != 0){
                printf("%d\n", WEXITSTATUS(status));
            }
        }
    }
    printf("Bye\n");
    exit(2);
}

??本人想象结果如下:

# 父进程的输出
Hello
0
2
Bye
# 子进程的输出
1
Bye
# 因为waitpid的存在,所以父进程的2在子进程的Bye之后
# 情况一
Hello
0
1
Bye
2
Bye
# 情况二
Hello
1
0
Bye
2
Bye

??运行结果如下所示:

$$$ ./make.sh 7.practise.c
Hello
0
1
Bye
2
Bye

八、execve()执行命令的示例:

??execve和fork配合使用的代码命令:

#include "csapp.h"
#define MAXARGS 128

int builtin_command(char** argv){
    if (!strcmp(argv[0], "quit")){
        exit(0); //碰到第一个为quit,则直接退出
    }else if (!strcmp(argv[0], "&")){
        return 1;//碰到第一个为&,那么返回1
    }
    return 0;
}

// 解析argv字符串参数的函数
/*
 具体的作用就是把buf这个字符串,把空格替换成'\0'停止符,前面的空格删除;
 然后把参一个一个传入到argv中;
*/
int parseline(char* buf, char** argv){
    char* delim;
    int argc;
    int bg;
    buf[strlen(buf)-1] = ' ';
    while(*buf && (*buf == ' '))
        buf++;
    argc = 0;
    while((delim = strchr(buf, ' '))){
        argv[argc++] = buf;
        *delim = '\0';
        buf = delim + 1;
        while(*buf && (*buf == ' '))
            buf++;
    }
    argv[argc] = NULL;
    if (argc == 0)
        return 1;
    if((bg = (*argv[argc -1] =='&')) != 0)
        argv[--argc] = NULL;
    return bg;
}

// 运行命令的函数
void eval(char* cmdline){
    char* argv[MAXARGS];
    char buf[MAXARGS];
    int bg;
    pid_t pid;
    strcpy(buf, cmdline);
    bg = parseline(buf, argv);
    if (argv[0] == NULL)
        return;
    if(!builtin_command(argv)){
        if((pid = Fork()) == 0){
            if (execve(argv[0], argv, environ) < 0){ //使用execve执行命令行参数
                printf("%s: Command not found.\n", argv[0]);
                printf("Then using execvp command\n");
                execvp(argv[0], argv); //如果上述失败,那么使用execvp执行命令,因为该程序使用了PATH信息
                exit(0);
            }
        }
        if(!bg){
            int status;
            if(waitpid(pid, &status, 0) < 0){
                unix_error("waitfg: waitpid error");
            }else{
                printf("%d %s", pid, cmdline);
            }
        }
        return;
    }
}
//获取环境变量
void print_variable(char* name){
    printf("%s=%s\n", name, getenv(name));
    return;
}
int main(int argc, char** argv){
    print_variable("PATH");
    char cmdline[MAXARGS];
    while(1){
        printf(">");
        Fgets(cmdline, MAXARGS, stdin);
        if (feof(stdin)){
            exit(0);
        }
        //运行
        eval(cmdline);
    }
    return 0;
}

??代码说明:

  • execve跟fork的区别在于:execve没有创建新的进程,就是完全覆盖了原来的进程程序
  • execve跟execvp的区别:前者无法使用到环境变量中的PATH信息,而后者可以利用到,所以后者可以执行类似于ls等命令

??运行结果如下所示:

$$$ ./make.sh 7.practise.c
>ls .
ls: Command not found.
Then using execvp command
test
4741 ls .
>pwd
pwd: Command not found.
Then using execvp command
/media/inspur/inference/pengzhikang/unix_learning/pthread/build/release
4768 pwd
>
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-03-16 22:58:21  更:2022-03-16 22:58:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 1:24:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码