当前位置: 首页 > news >正文

自己做的网站外国人能访问吗广告设计公司有哪些渠道通路

自己做的网站外国人能访问吗,广告设计公司有哪些渠道通路,导航网站怎么赚钱,价格合理的网站建设fork函数初始#include <unistd.h> pid_t fork(void); 返回值&#xff1a;自进程中返回0&#xff0c;父进程返回子进程id&#xff0c;出错返回-1进程调用fork&#xff0c;当控制转移到内核中的fork代码后&#xff0c;内核做&#xff1a;分配新的内存块和内核数据结构给子进…

fork函数初始

#include <unistd.h>
pid_t fork(void);
返回值:自进程中返回0,父进程返回子进程id,出错返回-1

进程调用fork,当控制转移到内核中的fork代码后,内核做:

  • 分配新的内存块和内核数据结构给子进程
  • 将父进程部分数据结构内容拷贝至子进程
  • 添加子进程到系统进程列表当中
  • fork返回,开始调度器调度
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{printf("begin\n");fork();printf("after\n");return 0;
}

fork之前,父进程运行;fork之后,创建子进程,调度器决定父子进程谁先被调用。

写时拷贝细节

当fork之后,父子进程共享代码,但是对数据任意一方进行修改,都会触发写时拷贝。可是,是如何触发的呢?操作系统又是如何得知的呢?这和页表的权限位有关,读写和可执行。操作系统在创建子进程的时候,会把数据的写权限取消掉,保留读的权限;当你要对这部分数据进行写入的时候,操作系统就会感知到,由于这部分是数据,操作系统不会异常结束进程,而是会再给你开辟一块空间,写入数据,这就是写时拷贝。

虚拟内存,地址空间,进程地址空间,程序地址空间这些名字实际上都是一个东西,那就是进程地址空间,这也是最准确的叫法。

进程终止

进程退出场景:

  • 代码运行完毕,结果正确
  • 代码运行完毕,结果不正确
  • 代码异常终止

进程常见退出方法:

  • return结束
  • exit
  • _exit

查询最近一次退出码:

echo $?

exit

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{printf("Linxu");exit(11);return 0;
}

_exit

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{printf("Linxu");_exit(12);return 0;
}

return 

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{printf("Linxu");return 0;
}

return 语句会在进程结束后,返回一个数字,叫退出码。告诉父进程,子进程的运行情况。C语言也会使用errno全局变量记录最近一次调用函数的情况。默认认为0是成功运行,其他值则是有异常。exit和_exit会设置退出码,发送信号,结束进程。

野指针,在操作系统上看就是,访问到了非写权限的地址,操作系统做出回应,终止进程

因此,我们也可以使用指令kill搭配选项终止进程。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{while(1){printf("pid : %d\n",getpid());sleep(1);}return 0;
}

使用kill -11 终止上面进程,即使该进程代码没问题,我也能通过发送信号,告诉操作系统该进程不正常,从而异常结束。

所以,进程是否能正常退出,除了代码的语法和逻辑有关,还和进程的维护有直接关系。总而言之,如果你的进程被黑了,权限被改了,那么你的代码就形同虚设了。

exit和_exit函数都是设置退出码,结束进程。那两者有什么区别呢?exit是库函数,而_exit是系统调用接口。exit在清理掉缓冲流等之后,接着调用_exit函数结束进程;而_exit直接就结束进程。

进程等待

僵尸进程情况:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{pid_t id = fork();if(id < 0){perror("fork");return 1;}else if(id == 0){int cnt = 5;while(cnt){printf("i am child, pid:%d, ppid:%d, cnt:%d\n",getpid(),getppid(),cnt);cnt--;sleep(1);}exit(0);}else{while(1){printf("i am father, pid:%d, ppid:%d\n",getpid(),getppid());sleep(1);}}return 0;
}

查询指令:

while :; do ps ajx | head -1 && ps ajx | grep testwait | grep -v grep;sleep 1;echo "------------";done

wait结束进程

包含的头文件

#include <sys/types.h>
#include <sys/wait.h>

创建10个进程,使用wait回收进程

#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define N 10
void runChild()
{int cnt = 5;while(cnt){printf("i am child, pid:%d, ppid:%d, cnt:%d\n",getpid(),getppid(),cnt);cnt--;sleep(1);}
}
int main()
{for(int i = 0; i < N;i++){pid_t id = fork();if(id == 0){runChild();exit(0);}printf("create child process: %d success\n",id);}for(int i = 0; i < N; i++){pid_t id = wait(NULL);if(id > 0){printf("wait: %d success\n",id);}}sleep(5);return 0;
}

进程替换

execl代码 执行可执行程序

单进程

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{printf("begin: i am a process  pid:%d, ppid:%d\n",getpid(),getppid());//这类方法的标准写法execl("/usr/bin/ls","ls","-a","-l",NULL);printf("after: i am a process  pid:%d, ppid:%d\n",getpid(),getppid());return 0;
}

原理:旧程序的代码和数据被切换成新程序的代码和数据,不替换环境变量

多进程

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{pid_t id = fork();if(id == 0){ printf("begin: i am a process  pid:%d, ppid:%d\n",getpid(),getppid());//这类方法的标准写法execl("/usr/bin/ls","ls","-a","-l",NULL);printf("after: i am a process  pid:%d, ppid:%d\n",getpid(),getppid());//exit(0);}//fatherelse{pid_t ret = waitpid(id,NULL,0);if(ret > 0){printf("wait success, father pid:%d, ret:%d\n",getpid(),ret);}}return 0;
}

程序替换接口

在Linux中一共有7个程序替换接口,6个库函数接口,1个系统接口execve;

7个接口没有本质区别,都是直接操作进程。不仅c和c++可执行程序可以被调用,像脚本语言,python,java等等语言都可以被调用,因为这些语言在操作系统看来就是一个个进程,没有区别。python也有类似execl接口的函数,只不过使用python语言进行包装,底层还是调用execl接口。

以ls指令为例,如下图解释:

这里参数的作用就是确定一个程序的路径,其次是执行方法,再次就是其他参数,如命令行参数

这6个库函数,带p的函数,指定环境变量PATH;带v的函数,使用字符数组传递后面的参数,不使用可变参数;带e的参数,可以传递环境变量;

上面我执行的ls指令是内部程序,外部程序也可以执行,如下面的代码:

otherExe可执行程序:

#include <iostream>
using namespace std;
int main()
{cout <<"helo Linux C++" <<endl;return 0;
}

mycommand可执行程序:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
//#include <sys/types.h>
int main()
{pid_t id = fork();if(id == 0){ printf("begin: i am a process  pid:%d, ppid:%d\n",getpid(),getppid());//这类方法的标准写法execl("./otherExe","otherExe",NULL);printf("after: i am a process  pid:%d, ppid:%d\n",getpid(),getppid());exit(0);}//fatherelse{pid_t ret = waitpid(id,NULL,0);if(ret > 0){printf("wait success, father pid:%d, ret:%d\n",getpid(),ret);}}return 0;
}

运行结果:

在mycommand程序中调用execl函数,进行程序替换,运行otherExe函数;注意这里是多进程,子进程和父进程互不影响,并发运行。环境变量不会被替换,环境变量具有全局属性,进程在被创建时,就存在了。虽然环境变量也属于数据,但是进程替换并不会替换环境变量,否则父子关系无法保证,该进程无法回收。

vim工具一次编译多个文件

.PHONY:all
all:otherExe mycommand
mycommand:mycommand.cgcc -o $@ $^
otherExe:otherExe.ccg++ -o $@ $^ -std=c++11 
.PHONY:clean
clean:rm -rf mycommand otherExe

上面execl替换外部程序的代码,我们可以使用简便的指令,实现一次编译多个文件,方法如上图的vim代码。

Linux形成的可执行程序是有格式,ELF,有表头,会存储进程入口地址,execl就是依靠这个地址实现进程替换。

如何上传环境变量:

  • 新增环境变量:使用putenv,把环境变量上传到调用进程的上下文中。
  • 覆盖环境变量:使用execl式的接口,要求末尾带e,如execle

覆盖环境变量

#include <iostream>
using namespace std;
int main(int argc,char* argv[],char* env[])
{cout <<"helo Linux C++" <<endl;int i = 0;cout <<"命令行参数" << endl;for(;argv[i]; i++){cout << i << " " << argv[i] << endl;}i = 0;for(; env[i]; i++){cout <<i << " " << env[i] <<endl;}return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{//putenv("MYENV=123456");pid_t id = fork();if(id == 0){ printf("begin: i am a process  pid:%d, ppid:%d\n",getpid(),getppid());char* const myenv[] = {"MYVAL=123","MYPATH=/usr/bin/XXX",NULL};execle("./otherExe", "otherExe", "-a", "-b", NULL, myenv);printf("after: i am a process  pid:%d, ppid:%d\n",getpid(),getppid());exit(0);}//fatherelse{pid_t ret = waitpid(id,NULL,0);if(ret > 0){printf("wait success, father pid:%d, ret:%d\n",getpid(),ret);}}return 0;
}

新增环境变量

#include <iostream>
using namespace std;
int main(int argc,char* argv[],char* env[])
{cout <<"helo Linux C++" <<endl;int i = 0;cout <<"命令行参数" << endl;for(;argv[i]; i++){cout << i << " " << argv[i] << endl;}i = 0;for(; env[i]; i++){cout <<i << " " << env[i] <<endl;}return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{putenv("MYENV=123456");pid_t id = fork();if(id == 0){ printf("begin: i am a process  pid:%d, ppid:%d\n",getpid(),getppid());char* const myenv[] = {"MYVAL=123","MYPATH=/usr/bin/XXX",NULL};execl("./otherExe", "otherExe", "-a", "-b", NULL);printf("after: i am a process  pid:%d, ppid:%d\n",getpid(),getppid());exit(0);}//fatherelse{pid_t ret = waitpid(id,NULL,0);if(ret > 0){printf("wait success, father pid:%d, ret:%d\n",getpid(),ret);}}return 0;
}

总结:

exec系列函数

  • l代表列表,参数使用列表一个个传参
  • v代表vector,参数使用数组传参
  • p代表PATH环境变量
  • e代表env环境变量

6个库函数只在参数上有区别,本质一样,底层最终都会调用一个系统调用接口execve

http://www.dtcms.com/a/430654.html

相关文章:

  • 分布式专题——24 Kafka功能扩展
  • 范式革命:RDMA 如何让网络成为 “分布式内存总线”
  • 如何弄公司网站青岛专业网站制作
  • Langchain4j笔记
  • 云计算介绍
  • 什么是Redis哨兵机制?
  • Web本体语言(OWL)
  • 快学快用系列:一文学会java后端WebApi开发
  • 网站加速器免费永久网站开发学习课程
  • SpringBoot 整合Jasypt 实现配置文件加密读取操作详解
  • apache 服务器如何使用
  • CI/CD 流水线与 agentic AI:如何创建自我纠正的 monorepos
  • Coze源码分析-资源库-编辑工作流-后端源码-IDL/API/应用服务层
  • 网站建设与维护课程设计报告书wordpress 多媒体管理系统
  • 一文了解国产算子编程语言 TileLang,TileLang 对国产开源生态的影响与启示
  • C#和Java正则表达式开发
  • 从零开始:MCP数据库助手(一)- 基础搭建
  • ORB_SLAM2原理及代码解析:SetPose() 函数
  • 蚌埠市建设学校网站网站排名权重怎么做
  • Android android.util.LruCache源码阅读
  • 安卓基础组件020-页面跳转传递数据001
  • Postman 学习笔记 IV:Workflow、Newman 与 Mock Server 实战技巧
  • 安卓基础组件016--第三方Toasty组件
  • ESNP LAB 笔记:配置静态BFD检测MPLS LDP LSP
  • Day30 | Java集合框架之Collections工具类
  • 【STM32项目开源】基于STM32的智能养殖场环境监测系统
  • 【Java并发】揭秘Lock体系 -- condition等待通知机制
  • 计算机网络-网络边缘网络核心
  • 安卓13_ROM修改定制化-----修改固件 去除主题防止恢复 破解主题等操作解析
  • 怎么做网站301重定向可口可乐公司的企业网站建设