系统编程-文件操作4

exec(鸠占鹊巢)

  • 查找文件:fins /usr

execl

#include <unistd.h> //read() write()
#include <stdio.h>
#include <string.h>
#include <errno.h>//errno 
/*open()*/
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>

/* dir open */
#include <sys/types.h>
#include <dirent.h>
int main()
{
    int ret=-1;
    //使用新进程镜像替换当前进程镜像
    //但是当前进程的ID被新进程使用
    //-->鸠占鹊巢
    //想看user/include下面的内容(路径+要执行的命令+命令的方式)
    //第一个参数:可执行文件的路径,之后的参数,可执行文件执行的方式
    //ret=execl("/bin/ls","ls","/usr/include","-l",NULL);
    //ret=execl("./exec1","exec1",NULL);
    //ret=execl("/usr/bin/gedit","gedit","dirCopy.c",NULL);
    //ret=execlp("gedit","gedit","dirCopy.c",NULL);//可以打开dirCopy.c文件
    /*ret=execlp("exec1","exec1",NULL);//运行不起来,不会循环打印hello world,因为不加路径,则会去系统找相应的命令,但是找不到,可以不指定需要执行文件的命令,启动该执行文件时,到系统默认路径下找该执行文件,若找到了则执行,否则出错返回
    
    if(-1==ret)
    {
        perror("execlp");
        return -1;
    }*/
        /*char *const argv[]={"ls","/usr/include","-l",NULL};
    ret=execv("/bin/ls",argv);*///运用数组将后面的放进数组里。
    char *const argv[]={"gedit","dirCopy.c",NULL};
    ret=execvp("gedit",argv);
    return 0;
}

  • 模拟一个终端,可以同时打开两个文件
#include <unistd.h> //read() write()
#include <string.h>
#include <stdio.h>
int main(int argc,char *argv[])
{
    pid_t pid=-1;
    pid=fork();
    if(pid>0)//父进程
    {
        while(1)
        {
            printf("this is parent\n");
            sleep(1);
        }
    }
    else if(0==pid)
    {
        //./a.out /bin/ls /usr/include -l
        int ret=-1;
        ret=execv(argv[1],argv+1);//argv+2:表示从第2个往后,直到碰到NULL
        if(-1==ret)
        {
            perror("execv");
            return -1;
        }
    }
    /*else if(-1==pid)
    {
        perror()
    }*/
    return 0;
}
//以下为运行结果

Paste_Image.png
Paste_Image.png

Paste_Image.png

模拟一个终端


#include <unistd.h> //read() write()
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char *getInput(char *argv[])
{
    int ret=-1;
    int i=0;
    char *pData=NULL;
    pData=(char *)malloc(64);
    while(EOF!=scanf("%s",pData))
    {
        printf("%s\n",pData);
        argv[i]=pData;
        i++;
        pData=(char *)malloc(64);
    }
    free(pData);
    argv[i]=NULL;
    return NULL;
}
void showArgv(char *argv[])
{
    int i=0;
    while(argv[i]!=NULL)
    {
        printf("%s\n",argv[i]);
        i++;
    }
}
int main(int argc,char *argvm[])
{
    char *argv[32]={NULL};
    while(1)
    {
        printf("MyTermal@sq$:");
        getInput(argv);

        pid_t pid=-1;
        pid=fork();
        if(0==pid)
        {
            int ret=-1;
            ret=execvp(argv[0],argv);
            if(ret==-1)
            {
                perror("execvp");
                return -1;
            }
        }
    }
    return 0;
}

Paste_Image.png

Paste_Image.png
  • 上一个程序没有处理僵尸进程,所以不完善

atexit(在程序正常结束的时候,调用)

  • 用户层,对相关的进行清理
  • 到内核层,也对相关的进行清理

//错误号被设置:出错可以看到错误信息,否则看不到

#include<stdio.h>
#include<stdlib.h>
void fun1()
{
    printf("fun1...\n");
}
void fun2()
{
    printf("fun2...\n");
}
void fun3()
{
    printf("fun3...\n");
}
//进程正常结束时首先在用户层做一些善后工作
//然后进入内核层做一些善后工作
int main(void)
{
    //atexit注册的函数会在进程正常结束后被执行
    //执行的顺序和注册的顺序相反
    atexit(fun1);
    atexit(fun2);
    atexit(fun3);
    

    printf("hello world\n");
    return 0;
}

Paste_Image.png
  • 加了exit(-1),就自杀了
#include<stdio.h>
#include<stdlib.h>
void fun1()
{
    printf("fun1...\n");
}
void fun2()
{
    printf("fun2...\n");
}
void fun3()
{
    printf("fun3...\n");
}
//进程正常结束时首先在用户层做一些善后工作
//然后进入内核层做一些善后工作
int main(void)
{
    //atexit注册的函数会在进程正常结束后被执行
    //执行的顺序和注册的顺序相反
    atexit(fun1);
    atexit(fun2);
    atexit(fun3);
    
    exit(-1);//自杀
    printf("hello world\n");
    return 0;
}

//不会执行hello world

Paste_Image.png

abort(非正常结束)

#include<stdio.h>
#include<stdlib.h>
void fun1()
{
    printf("fun1...\n");
}
void fun2()
{
    printf("fun2...\n");
}
void fun3()
{
    printf("fun3...\n");
}
//进程正常结束时首先在用户层做一些善后工作
//然后进入内核层做一些善后工作
int main(void)
{
    //atexit注册的函数会在进程正常结束后被执行
    //执行的顺序和注册的顺序相反
    atexit(fun1);
    atexit(fun2);
    atexit(fun3);
    abort();//已放弃(核心已转储)
//  exit(-1);//自杀
    printf("hello world\n");
    return 0;
}
//用了abort,就段错误

  • 可以退出整个程序的
  1. return 0;exit():会首先在用户层做一些善后工作,然后进入内核层组一些善后工作
  1. _exit():直接进入内核层作一些善后工作
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
void fun1()
{
    printf("fun1...\n");
}
void fun2()
{
    printf("fun2...\n");
}
void fun3()
{
    printf("fun3...\n");
}
//进程正常结束时首先在用户层做一些善后工作
//然后进入内核层做一些善后工作
int main(void)
{
    //atexit注册的函数会在进程正常结束后被执行
    //执行的顺序和注册的顺序相反
    atexit(fun1);
    atexit(fun2);
    atexit(fun3);
    _exit(-1);//也能退出程序(进程结束)
//  abort();//已放弃(核心已转储)
//  exit(-1);//自杀
    printf("hello world\n");
    return 0;
}

//用了_exit(-1):不会进行运行直接退出

作业

  1. 完善文件拷贝(假如将一个目录拷贝到了文件里,进行分析)
  2. 进程的状态以及状态间的转化
  3. 独立完成模仿终端代码

进程与通信

  • IPC:代表进程间

进程间的通信方式

  1. 管道通信:命名管道和无名管道
  • env | grep unix :grep是匹配规则,只要数据符合规则,则全部都提取出来
Paste_Image.png

pipe(管道通信)

  • 父进程发送消息,子进程接收消息
  • 如果要换成子进程发消息,父进程接收
#include<unistd.h> //pipe() fork()
#include<stdio.h>
#include<string.h>
int main()
{
    int pipefd[2]={-1};//管道两端,一端读,一端写
    int ret=-1;
    //创建一个管道(不属于父进程)
    ret=pipe(pipefd);
    if(-1==ret)
    {
        perror("pipe");//创建失败
        return -1;
    }
    //创建一个子进程
    pid_t pid=-1;
    pid=fork();
    if(pid>0)//父进程
    {
        close(pipefd[0]);//一个说
        while(1)
        {
            write(pipefd[1],"Hello child",11);
            sleep(1);
        }
    }
    else if(pid==0)//子进程
    {   
        close(pipefd[1]);//一个听,不能同时说,同时听
        char caBuf[32]={'\0'};
        while(1)
        {
            memset(caBuf,'\0',sizeof(caBuf));//清空读掉的空间
            read(pipefd[0],caBuf,11);
            printf("%s\n",caBuf);
            sleep(1);
        }
    }
    else if(pid==-1)//创建进程失败
    {
        perror("fork");
        return -1;
    }
    return 0;
}

  • 父进程与子进程之间进行相互通信
#include<unistd.h> //pipe() fork()
#include<stdio.h>
#include<string.h>
//通过pipe()函数创建的管道属于无名管道,只能在父子进程间使用,或者子进程间使用,创建该管道的进程一旦结束,则该无名管道将会被销毁
int main()
{
    int pipefd[2]={-1};//管道两端,一端读,一端写
    int ret=-1;
    //创建一个管道(不属于父进程),管道两边的描述符存储到pipefd数组中
    //pipefd[0]表示数据流出端,可以从此端读取数据
    //pipefd[1]表示数据进入端,可以往此端写入数据
    ret=pipe(pipefd);
    if(-1==ret)
    {
        perror("pipe");//创建失败
        return -1;
    }
    //创建一个子进程
    pid_t pid=-1;
    //管道的创建的是在内核中,不独立属于进程
    //所以,fork产生子进程是并不会再次创建一个管道
    //只是对管道文件描述符进行了一次拷贝
    pid=fork();
    if(pid>0)//父进程
    {
        int iSign=0;
        char caBuf[64]={'\0'};
        while(1)
        {
            memset(caBuf,'\0',sizeof(caBuf));
            if(0==iSign)
            {
                printf("parent-input data:");
                scanf("%s",caBuf);
                write(pipefd[1],caBuf,strlen(caBuf));
                iSign=1;
            }
            else if(1==iSign)
            {
                read(pipefd[0],caBuf,sizeof(caBuf));
                printf("child says:%s\n",caBuf);
                iSign=0;
            }
            sleep(1);
        }
    }
    else if(pid==0)//子进程
    {   
        int iSign=1;
        char caBuf[64]={'\0'};
        while(1)
        {
            memset(caBuf,'\0',sizeof(caBuf));
            if(0==iSign)
            {
                read(pipefd[0],caBuf,sizeof(caBuf));
                printf("parent says:%s\n", caBuf);
                iSign=1;
            }
            else if(1==iSign)
            {
                printf("child-input data:");
                scanf("%s",caBuf);
                write(pipefd[1],caBuf,strlen(caBuf));
                iSign=0;
            }
            sleep(1);
        }
    }
    else if(pid==-1)//创建进程失败
    {
        perror("fork");
        return -1;
    }   return 0;
}

Paste_Image.png

进程在运行中不断改变其运行状态,而运行的进程有三个基本状态。

  1. 就绪状态:当进程已分配到除CPU以外所有必要的资源,只要获得处理器便可立即执行。
  2. 执行状态:当进程已获得处理器,其程序正在处理器上执行。
  3. 阻塞状态:正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态,而引起进程阻塞的事件可能有很多种,如等待I/O完成,申请缓冲区不能满足、等待信号等。
    而一个进程在运行期间,会不断地从一个状态转换到另一个状态。于是便有了进程的三种基本状态间的相互转换,如下示意图:
Paste_Image.png
  1. 就绪->执行:处于就绪状态的进程,当进程调度程序为之分配了处理器后,该进程便由就绪状态转变为执行状态。
  2. 执行->就绪:处于执行状态的进程在其执行进程中,因分配给它的一个时间片已用完而不得不让处理器,于是进程从执行状态转换成就绪状态。
  3. 执行->阻塞:正在执行的进程因等待某种事件发生而无法继续执行时,便从执行状态变成阻塞状态。
  4. 阻塞->就绪:处于阻塞状态的进程,若其等待的事件已经发生,于是进程由阻塞状态转变为就绪状态。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • 又来到了一个老生常谈的问题,应用层软件开发的程序员要不要了解和深入学习操作系统呢? 今天就这个问题开始,来谈谈操...
    tangsl阅读 4,085评论 0 23
  • 第一章 A:操作系统:是管理计算机硬件并提供应用程序运行环境的软件 1)资源分配器,管理资源、分配资源 2)控制程...
    ZoeyeoZ阅读 1,093评论 0 4
  • 系统与网络编程 exec的使用 找一个函数:find /usr gedit execl 使用调用系统lsint e...
    I踏雪寻梅阅读 420评论 0 1
  • 不用提早地地拾点,不去费劲地让行李箱的两个链扣重新碰面,就简单的拉紧背包,二等的座位也能充分地伸腿,去到想去的地方...
    我有眼睛zz阅读 330评论 0 2
  • 冬日的影子 不同于夏日 太阳也是 只够晒黑我的头发 还有眼珠 所以影子 也只有黑黑的头发 和黑黑的眼
    Lonelyran阅读 136评论 1 3