进程替换与基础IO

进程替换与基础IO

1.进程程序替换原理

因为父进程创建出来的子进程和父进程拥有相同的代码段,所以,子进程看到的代码和父进程是一样的。
当我们想要让子进程执行不同的程序时候,就需要让子进程调用进程程序替换的接口,从而让子进程执行不一样的代码

原理:用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动
例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。简单来说就是替换进程的代码段和数据段,更新堆栈

图解:
在这里插入图片描述

2.exec函数簇

1.替换函数:

有六种以exec开头的函数,统称exec函数:

#include <unistd.h>`
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ...,char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
2.函数解释
  • 这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
  • 如果调用出错则返回-1
  • 所以exec函数只有出错的返回值而没有成功的返回值。
3.命名理解
  • l(list) : 表示参数采用列表,传递给可执行的程序的命令行参数,第一个参数,需要可执行程序本身,如果需要传递多个参数,则用“,”进行间隔,末尾以NULL结尾
  • v(vector) : 参数用数组,传递给可执行的程序的命令行参数,以指针数组的方式进行传递。第一个参数,需要可执行程序本身,多个参数就都放到数组当中,末尾以NULL结尾
  • p(path) : 有p自动搜索环境变量PATH,可执行程序,可以带有路径,也可以不带路径
  • e(env) : 表示自己维护环境变量,程序员调用该函数的时候,需要自己组织环境变量传递给函数
4.总结:

在这里插入图片描述

3.函数之间的区别

只有execve是真正的系统调用函数,其他五个函数最终都调用excve,关系如图:
在这里插入图片描述

4.C语言下的文件接口

1.fopen

**FILE *fopen(const char path,const char mode);

  • path :带有路径的文件名称,(如果说不带有路径,打开的文件可以是在当前路径下)
  • mode :打开文件的方式
  • r :只读模式打开
    文件流是指向了文件起始位置
  • r+:以可读可写的方式打开
    文件流是指向了文件起始位置
  • w:当前文件如果存在,则截断(清空文件内容)文件当前文件不存在,则创建一个新文件
  • w+:以可读可写的方式打开
    当前文件如果存在,则截断(清空文件内容)文件当前文件不存在,则创建一个新文件
  • a:追加写
    如果当前文件不存在,则创建文件
    如果当前文件存在,则将文件流指针指向文件末尾进行写。
  • a+:可以读,也可以追加写
    如果文件不存在,则创建文件
    读的位置被初始化到文件的头,但是追加的写的时候,从文件的末尾开始追加
  • 返回值:
    成功:返回文件流指针FILE*
    失败:返回NULL
2.fwrite

*size_t fwrite(const void*ptr,size_t size,size_t nmemb,FILE stream);

  • 参数:
    ptr:想往文件当中写什么内容
    size:定义往文件当中写的时候,一个块是多大,单位字节;(通常定义为一个字节)
    nmemb :期望写多少块
    stream:文件流指针
  • 返回值:成功写入到文件当中的块的个数(成功写入到文件当中的字节数量)
3.fread

size_t fread(void ptr,size_t size,size_t nmemb,FILEstream);

  • 参数:
    ptr:将从文件当中读到的内容保存到ptr指向的内存空间当中
    size:定义从文件当中读的时候,一个块是多大,单位字节;(通常定义为一个字节)
    nmemb :期望读多少块
    stream:文件流指针
  • 返回值: 返回成功读入的文件块的个数
4.fseek

int fseek (FILE*stream, long offset,int whence);

  • 作用:移动文件流指针的位.置
  • 参数:
    stream:文件流指针offset :偏移量
    whence :将文件流指针便宜到什么位置
    SEEK_SET:文件头部
    SEEK_CUR:当前文件流指针的位置SEEK_END:文件末尾
    返回值:成功:0失败:-1

5.系统调用的文件接口

1.open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
  • pathname: 要打开或创建的目标文件
  • flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
  • 参数:
    O_RDONLY: 只读打开
    O_WRONLY: 只写打开
    O_RDWR : 读,写打开
    这三个常量,必须指定一个且只能指定一个
    O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
    O_APPEND: 追加写
  • 返回值:成功:新打开的文件描述符
2.write

*ssize_t write(int fd,const void buf,size_t count) ;

  • 参数:
  • fd:文件描述符
  • buf:将buf指向的内容写到文件当中去
  • count:期望写多少字节
  • 返回值:返回写入的字节数量
3.read

*ssize_t read(int fd, void buf,size_t count) ;

  • 参数:
  • fd:文件描述符
  • buf:将从文件当中读到的内容写到buf指向的空间当中
  • count:期望读多少字节
  • 返回值:
    返回读到的字节数量
4.lseek

off_t lseek (int fd, off_t offset,int whence) ;

  • 参数:
  • fd:文件描述符
  • offset:偏移量,单位字节
  • whence:偏移的位置
  • SEEK_SET:文件头部
  • SEEK_CUR:当前文件流指针的位置
  • SEEK_END:文件末尾
  • 返回值:
    成功:返回偏移的位置,单位字节失败:-1

6.文件描述符

  • 文件描述符:Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2.对应的物理设备一般是:键盘,显示器,显示器
  • 分配规则:不是固定进行分配,而是按照最小未使用原则进行分配
    代码验证:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
 	close(0);
 	//close(2);
   	int fd = open("myfile", O_RDONLY);
   	if(fd < 0){
       	perror("open");
       	return 1;
   }
 	printf("fd: %d\n", fd);
   	close(fd);
   	return 0;
}
  • 当我们打开文件时,操作系统要创建相应的数据结构来描述目标文件,于是就有了file结构体
  • 表示一个已经打开的文件对象,进程执行open系统调用,所以必须是进程和文件关联起来。
  • 每个进程都有一个指针*files,指向一张表files_struct,该表最重要的部分包含一个指针数组,每个元素都是一个指向打开文件的指针。
  • 本质上文件描述符就是该数组的下标,所以文件描述符对应相应的文件

内核角度如图:
在这里插入图片描述

7.重定向

符号:

  • 清空重定向:>
  • 追加重定向:>>

接口:

  • int dup2(int oldrd.int newfd);
  • 作用:将newfd的值重定向为oldfd,newfd拷贝oldfd
  • 参数:oldfd/newfd均是文件描述符
  • 成功:1.关闭newfd
    2. 让newfd指向oldfd对应的struct file*结构体
  • 失败:1.如果oldfd是一个非法/无效的文件描述符,则重定向失败;newfd没有变化
    2.如果oldfd和newfd的值相等,则什么事情都不干

内核角度:
在这里插入图片描述

8.静态库与动态库

1.动态库
  • 概念:静态库与动态库都是程序代码的集合(二进制文件),调用者只用关注如何使用,不必内部实现
  • 动态库:
    windows:没有前缀,后缀为dll
    Linux:前缀为lib,后缀为.so
  • 生成:
    使用gcc或g++编译器:-fPIC、 -shard
    生成动态库的代码不需要包含main函数(程序入口函数)

具体步骤:

1.编写动态库文件

2.哪些方式可以让程序找到动态库:
1.将动态库放到可执行程序的路径下(不推荐)
2.配置LD_LIBRARY_PATH(推荐的常用手段)
动态库的环境变量:LD_LIBRARY_PATH
3.放到系统库的路径下(极力不推荐)

进入~/.bash_profile或者 ~/.bashrc文件中配置环境变量LD_LIBRARY_PATH
在这里插入图片描述
在这里插入图片描述
3.使用动态库文件,引入动态库对应的头文件

2.静态库
  • 静态库:
    windows:没有前缀,后缀为.lib
    Linux:前缀为lib,后缀为.a
  • 生成:
    第一阶段:使用gcc或g++将源代码编译成为目标程序(.o)
    第二阶段,使用ar -rc命令编译目标程序为静态库
    ar -rc [ 静态库文件名称] [目标程序]

9.软硬连接的理解

软链接:目标文件的快捷方式(通过名字引用)
生成:ln -s 源文件 软连接文件
1.修改软连接文件,源文件也会被修改
2源文件如果被删除,软连接文件还在的,修改软连接文件。会重新建立源文件,重新建立链接关系,所以在删除源文件的时候,将软链接文件也删掉,防止后患

硬链接:目标文件的替身(通过inode引用)
生成:ln 源文件 硬链接文件

  • 14
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值