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

seo如何根据网站数据做报表河南企业做网站

seo如何根据网站数据做报表,河南企业做网站,企业官网的作用,aso.net 网站开发目录 1. 进程创建 1.1 fork函数 1.2 fork系统调用内部宏观流程 1.3 fork后子进程执行位置分析 1.4 fork后共享代码分析 1.5 fork返回值 1.6 写时拷贝 1.7 fork常规用法 1.8 fork调用失败的原因 2.进程终止 2.1 进程退出场景 2.2 strerror函数—返回描述错误号的字符… 目录 1. 进程创建 1.1 fork函数 1.2 fork系统调用内部宏观流程 1.3 fork后子进程执行位置分析 1.4 fork后共享代码分析 1.5 fork返回值 1.6 写时拷贝 1.7 fork常规用法 1.8 fork调用失败的原因 2.进程终止 2.1 进程退出场景 2.2 strerror函数—返回描述错误号的字符串 2.3 进程常见退出方法 2.4 _exit函数和exit函数 2.5 return退出 3. 进程等待 3.1 进程等待必要性 3.2 进程等待方法 3.3 获取子进程status 3.4 进程阻塞等待和非阻塞等待 3.5 waitpid系统调用接口分析 3.6 阻塞等待代码和基于非阻塞调用的轮询检测方案 4. 进程程序替换 4.1 替换原理 4.2 替换函数 4.3 函数解释 4.4 命名理解 4.5 实现简易shell 5. 函数和进程之间的相似性 1. 进程创建 1.1 fork函数 在linux中fork函数时非常重要的函数它从已存在进程中创建一个新进程。新进程为子进程而原进程为父进程。 #include unistd.h pid_t fork(void); 返回值子进程中返回0父进程返回子进程id出错返回-1 1.2 fork系统调用内部宏观流程 进程调用fork当控制转移到内核中的fork代码后内核做 分配新的内存块和内核数据结构给子进程将父进程部分数据结构内容拷贝至子进程添加子进程到系统进程列表当中fork返回开始调度器调度 fork创建子进程系统中多了一个进程及包含进程对应的PCB结构体以及对应的地址空间及页表映射关系并将代码和数据加载到内存中并将该进程加载到运行队列等待操作系统调度器的调度一旦该进程被调度起来CPU就可以通过代码和数据及地址空间和页表映射在物理内存找到对应的代码进行运行  当一个进程调用fork之后就有两个二进制代码相同的进程。而且它们都运行到相同的地方。但每个进程都将可以 开始它们自己的旅程看如下程序。 int main( void ) {pid_t pid;printf(Before: pid is %d\n, getpid());if ( (pidfork()) -1 )perror(fork()),exit(1);printf(After:pid is %d, fork return %d\n, getpid(), pid);sleep(1);return 0; } 运行结果 [rootlocalhost linux]# ./a.out Before: pid is 43676 After:pid is 43676, fork return 43677 After:pid is 43677, fork return 0 这里看到了三行输出一行before两行after。进程43676先打印before消息然后它有打印after。另一个after 消息有43677打印的。注意到进程43677没有打印before为什么呢如下图所示  所以fork之前父进程独立执行fork之后父子两个执行流分别执行。注意fork之后谁先执行完全由调度器决定。 1.3 fork后子进程执行位置分析 fork前后父子进程所有代码共享 代码汇编后加载到内存都有与之对应的地址因为进程随时可能被中断可能并没执行结束下次回来还必须从之前的位置继续执行不是最开始位置就需要要求CPU必须随时记录当前进程执行的位置所以CPU有对应的寄存器数据EIPPC指针也叫做程序计数器用于记录当前正在执行代码的下一行代码的地址因此在进程切换时需要将寄存器信息带走上下文数据。 寄存器在CPU内只有一份切换进程必须带走数据寄存器内的数据是可以有多份的寄存器上下文数据 创建子进程的时候也会将上下文数据给子进程解释了fork之后子进程不会从before处运行虽然父子进程各自调度各自会修改EIP但是不重要了子进程已经认为自己的EIP起始值是fork之后的代码 1.4 fork后共享代码分析 创建子进程给予进程分配对应的内核结构必须子进程自己独有了因为进程具有独立性理论上子进程也要有自己的代码和数据可是一般而言我们没有加载的过程也就是说子进程没有自己的代码和数据所以子进程只能”使用“父进程的代码和数据 代码都是不可被写的只能读取所以父子共享没有问题 数据可能被修改的所以必须分离 对于数据而言 创建进程的时候就直接拷贝分离吗导致可能拷贝子进程根本就不会用到的数据空间即便是用到也可能只是只读编译器在编译时尚且知道节省空间操作系统同样如此如分批加载挂起状态因此创建子进程不需要将不会被访问的或者只读取的数据再去拷贝一份浪费空间 但是还有必须拷贝的数据什么样的数据值得拷贝将来会被父子进程写入的数据如上图gval或者接收fork返回值的变量 一般而言即便是操作系统也无法知道那些空间可能被写入即便是提前拷贝了也可能不会立马使用因此造成空间浪费所以操作系统提供了写时拷贝技术来对父子进程的数据进行分离 1.5 fork返回值 子进程返回0父进程返回的是子进程的pid 1.6 写时拷贝 通常父子代码共享父子再不写入时数据也是共享的当任意一方试图写入便以写时拷贝的方式各自一份副本。具体见下图:  因为有写时拷贝技术的存在所以父子进程得以彻底分离完成了进程的独立性的技术保证写时拷贝的好处写时拷贝只在写入数据时发生拷贝且对只读数据和代码不发生拷贝节省空间写时拷贝是一种延时申请技术可以提高整机内存的使用效率 1.7 fork常规用法 一个父进程希望复制自己使父子进程同时执行不同的代码段。例如父进程等待客户端请求生成子进程来处理请求。一个进程要执行一个不同的程序。例如子进程从fork返回后调用exec函数。 1.8 fork调用失败的原因 系统中有太多的进程实际用户的进程数超过了限制 2.进程终止 进程终止时操作系统本质上释放进程申请的相关内核数据结构和对应的代码和数据本质上是释放资源 2.1 进程退出场景 进程终止的常见方式         a. 代码跑完结果正确         b. 代码跑完结果错误         c. 代码没有跑完进程崩溃信号部分 指针a和b方式涉及问题 main函数的返回值main函数返回值的意义是什么return 0; 含义是什么为什么总是0其他值是否可以 main函数的返回值并不是总是0,返回0表示程序sucess非0表示运行结果不正确。 意义一main函数的返回值适用于返回上一级进程用来评判该进程执行结果用的为进程的退出码。 意义二非零值有无数个不同的非零值就可以标识不同的错误原因在我们程序运行结束之后结果不正确时根据返回码方便定位错误的原因细节 2.2 strerror函数—返回描述错误号的字符串 #include string.hchar *strerror(int errnum);int strerror_r(int errnum, char *buf, size_t buflen);/* XSI-compliant */char *strerror_r(int errnum, char *buf, size_t buflen);/* GNU-specific */#includeunistd.h #includestdio.h #includesys/types.h #includestring.h int main(){printf(Hello world! pid %d, ppid %d\n, getpid(), getppid());for(int i 0; i 150; i){printf(%d: %s\n, i, strerror(i));}return 0; } 2.3 进程常见退出方法 正常终止可以通过 echo $? 查看进程退出码 1. 从main返回 2. 调用exit 3. _exit 异常退出 ctrl c信号终止 2.4 _exit函数和exit函数 _exit函数是系统提供的系统调用接口 #include unistd.h void _exit(int status);参数status 定义了进程的终止状态父进程通过wait来获取该值 说明虽然status是int但是仅有低8位可以被父进程所用。所以_exit(-1)时在终端执行$?发现返回值是255。 exit函数是C语言库提供的接口 #include unistd.h void exit(int status); exit 或者 _exit 在任何地方调用都表示直接终止进程 Linux提供了系统调用接口_exit()函数在unistd.h头文件中而C的库函数exit底层实则封装了系统调用接口_exit 执行用户通过 atexit或on_exit定义的清理函数。关闭所有打开的流所有的缓存数据均被写入调用_exit 测试代码 int main() {printf(hello);exit(0); } 运行结果: [rootlocalhost linux]# ./a.out hello[rootlocalhost linux]# int main() {printf(hello);_exit(0); } 运行结果: [rootlocalhost linux]# ./a.out [rootlocalhost linux]# 分析图   2.5 return退出 return是一种更常见的退出进程方法。执行return n等同于执行exit(n),因为调用main的运行时函数会将main的返 回值当做 exit的参数。 有且只有在main函数内return语句就是终止进程的return退出码 3. 进程等待 3.1 进程等待必要性 之前讲过子进程退出父进程如果不管不顾就可能造成‘僵尸进程’的问题进而造成内存泄漏。另外进程一旦变成僵尸状态那就刀枪不入“杀人不眨眼”的kill -9 也无能为力因为谁也没有办法杀死一个已经死去的进程。最后父进程派给子进程的任务完成的如何我们需要知道。如子进程运行完成结果对还是不对 或者是否正常退出。父进程通过进程等待的方式回收子进程资源获取子进程退出信息 3.2 进程等待方法 wait方法 #includesys/types.h #includesys/wait.h pid_t wait(int*status); 返回值成功返回被等待进程pid失败返回-1。 参数输出型参数获取子进程退出状态,不关心则可以设置成为NULL waitpid方法 pid_ t waitpid(pid_t pid, int *status, int options); 返回值当正常返回的时候waitpid返回收集到的子进程的进程ID如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在 参数pidPid-1,等待任一个子进程。与wait等效。Pid0.等待其进程ID与pid相等的子进程。status:WIFEXITED(status): 若为正常终止子进程返回的状态则为真。查看进程是否是正常退出WEXITSTATUS(status): 若WIFEXITED非零提取子进程退出码。查看进程的退出码options:WNOHANG: 若pid指定的子进程没有结束则waitpid()函数返回0不予以等待。若正常结束则返回该子进 程的ID。 如果子进程已经退出调用wait/waitpid时wait/waitpid会立即返回并且释放资源获得子进程退 出信息。如果在任意时刻调用wait/waitpid子进程存在且正常运行则进程可能阻塞。如果不存在该子进程则立即出错返回。option默认为0表示阻塞等待status为输出型参数waitpid(pid, NULL, 0) wait(NULL) 3.3 获取子进程status wait和waitpid都有一个status参数该参数是一个输出型参数由操作系统填充。如果传递NULL表示不关心子进程的退出状态信息。否则操作系统会根据该参数将子进程的退出信息反馈给父进程。status不能简单的当作整形来看待可以当作位图来看待具体细节如下图只研究status低16比特 位  测试代码 #include sys/wait.h #include stdio.h #include stdlib.h #include string.h #include errno.h int main() {pid_t pid;if ( (pidfork()) -1 )perror(fork);exit(1);if ( pid 0 ){//子进程休眠20秒会变成僵尸进程//需要父进程等待回收sleep(20);exit(10);} else {//父进程int st;int ret wait(st);//阻塞等待if ( ret 0 ( st 0X7F ) 0 ){ // 正常退出//子进程退出码printf(child exit code:%d\n, (st8)0XFF);} else if( ret 0 ) { // 异常退出//子进程退出信号printf(sig code : %d\n, st0X7F );}}return 0; } 测试结果 [rootlocalhost linux]# ./a.out #等20秒退出child exit code:10 [rootlocalhost linux]# ./a.out #在其他终端kill掉sig code : 9进程异常退出或者崩溃本质是操作系统杀掉了你的进程 操作系统如何杀掉进程呢本质是通过发送信号的方式  父进程通过wait或者waitpid可以拿到进程的退出结果为什么要用wait/waitpid函数呢直接全局变量不行吗 答案是不行因为进程具有独立性其创建子进程虽然具有相同虚拟内存地址但是数据会发生写时拷贝父进程无法获取到况且如果是信号更是无法获取 既然进程具有独立性进程退出码不也是子进程的数据吗父进程又凭什么拿到呢wait/waitpid究竟干了什么呢 因为wait、waitpid是系统调用接口是系统创建的结构可以访问内核本质便是读取子进程的task_struct结构此结构肯定包含了对应的信号码和退出码 3.4 进程阻塞等待和非阻塞等待 optionsWNOHANG选项代表父进程非阻塞等待本质为了避免魔术数字#define WNOHANG 1 Linux C语言写的 - 系统调用接口 - OS自己提供的接口 -就是C语言函数 - 系统提供的一般大写的标记位 WNOHANG,其实就是宏定义 WNOHANG —— Wait No Hang(等待过程中没夯住)夯住本质就是指这个进程没有被CPU调度要么是在阻塞队列要么是在等待被调度 3.5 waitpid系统调用接口分析 阻塞等待和非阻塞等待一般都是在内核中阻塞等待被唤醒如scanf和cin底层必定封装了系统调用阻塞等待父进程通过调用waitpid来进行等待如果子进程没有退出waitpid这个系统调用立马返回非阻塞 3.6 阻塞等待代码和基于非阻塞调用的轮询检测方案 阻塞等待 #includestdio.h #includeunistd.h #includesys/wait.h #includestdlib.h #includesys/types.h #includestring.h int main(){pid_t id fork();if(id 0){perror(fork);exit(1);//表示进程运行完毕结果不正确}else if(id 0){//子进程int cnt 5;while(cnt){printf(cnt: %d, 我是子进程, pid : %d, ppid : %d\n, cnt, getpid(), getppid());sleep(1);cnt--;}exit(111);}else{//父进程printf(我是父进程, pid %d, ppid %d \n,getpid(), getppid());int status 0;pid_t ret waitpid(id, status, 0);//printf(获取子进程退出信号: %d \n获取子进程退出码 %d\n, status 0x7F,(status 8) 0xFF);//pid_t ret wait(NULL);//阻塞方式进行等待if(WIFEXITED(status)){printf(等待进程成功, ret %d, 子进程退出码:%d\n, ret, WEXITSTATUS(status));}}return 0; }基于非阻塞调用的轮询检测方案 #includeiostream #includevector #includestdio.h #includestdlib.h #includeunistd.h #includesys/types.h #includesys/wait.htypedef void(*handler_t)(); std::vectorhandler_t handlers;void fun_one(){printf(这是一个临时任务1\n); } void fun_two(){printf(这是一个临时任务2\n); }void Load(){handlers.push_back(fun_one);handlers.push_back(fun_two); }int main(){pid_t id fork();if(id 0){//子进程int cnt 5;while(cnt--){printf(我是子进程:%d\n, cnt);sleep(1);}exit(11);}else{//父进程int quit 0;while(!quit){int status 0;int res waitpid(id, status, WNOHANG);if(res 0){printf(进程等待成功退出状态码:%d\n, WEXITSTATUS(status));quit 1;}else if(res 0){printf(等待子进程退出处理其他事情中......\n);if(handlers.empty()){Load();}for(auto e : handlers){e();}}else{printf(进程等待错误\n);quit 1;}sleep(1);}}return 0; } 4. 进程程序替换 4.1 替换原理 fork之后父子进程各自执行代码的一部分—如果子进程就想执行一个全新的程序呢 进程的程序替换来完成这个功能 程序替换是通过特定的接口加载磁盘上的一个全新的程序代码和数据加载到调用进程的地址空间中使得子进程拥有自己的代码   用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数 以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动 例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。 进程替换的本质是加载新的代码和数据到内存改变子进程页表的映射关系完成替换 4.2 替换函数 其实有六种以exec开头的函数,统称exec函数: 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[]); int execvpe(const char *file, char *const argv[],char *const envp[]); //使用可变参数列表 实际Linux提供了七个替换函数额外一个 int execve(const char *path, char *const argv[], char *const envp[]); 4.3 函数解释 这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。如果调用出错则返回-1所以exec函数只有出错的返回值而没有成功的返回值。 4.4 命名理解 这些函数原型看起来很容易混,但只要掌握了规律就很好记。 l(list) : 表示参数采用列表 v(vector) : 参数用数组 p(path) : 有p自动搜索环境变量PATH e(env) : 表示自己维护环境变量  exec调用举例如下: #include unistd.h int main() {char* const argv[] { ps, -ef, NULL };char* const envp[] { PATH/bin:/usr/bin, TERMconsole, NULL };execl(/bin/ps, ps, -ef, NULL);// 带p的可以使用环境变量PATH无需写全路径execlp(ps, ps, -ef, NULL);// 带e的需要自己组装环境变量execle(ps, ps, -ef, NULL, envp);execv(/bin/ps, argv);// 带p的可以使用环境变量PATH无需写全路径execvp(ps, argv);// 带e的需要自己组装环境变量execve(/bin/ps, argv, envp);exit(0); } 事实上,只有execve是真正的系统调用,其它五个函数最终都调用 execve,所以execve在man手册 第2节,其它函数在 man手册第3节。这些函数之间的关系如下图所示。 下图exec函数族 一个完整的例子:   4.5 实现简易shell 用下图的时间轴来表示事件的发生次序。其中时间从左向右。shell由标识为sh的方块代表它随着时间的流逝从左 向右移动。shell从用户读入字符串ls。shell建立一个新的进程然后在那个进程中运行ls程序并等待那个进程结 束。  然后shell读取新的一行输入建立一个新的进程在这个进程中运行程序 并等待这个进程结束。 所以要写一个shell需要循环以下过程: 获取命令行解析命令行建立一个子进程fork替换子进程execvp父进程等待子进程退出wait   #includestdio.h #includestdlib.h #includestring.h #includeunistd.h #includesys/wait.h #includesys/types.h#define NUM 1024 #define SIZE 32 char cmd_line[NUM];void dealStr(char* str, char** argv) {char* dealstr NULL;const char* sep ;size_t i 0;for (dealstr strtok(str, sep); dealstr ! NULL; dealstr strtok(NULL, sep)) {if (i SIZE) {argv[i] dealstr;i;}}if(strcmp(argv[0], ls) 0){argv[i] (char*)--colorauto;}argv[i] NULL; }//shell运行原理通过让子进程执行命令父进程等待解析命令 int main(){while(1){//1.打印提示信息printf([rootlocalhost myshell]#);fflush(stdout);//2.获取用户输入memset(cmd_line, \0, sizeof cmd_line);char *g_argv[SIZE] { NULL };if(fgets(cmd_line, sizeof cmd_line, stdin) NULL){continue;}cmd_line[strlen(cmd_line) - 1] \0;//printf(echo:%s\n, cmd_line);//3.命令行字符串分割dealStr(cmd_line, g_argv); //4.TODO 内置命令让父进程(shell)自己执行的命令叫做内置命令内建命令// 内建命令本质就是shell中的一个函数调用if(strcmp(cd, g_argv[0]) 0){//not child execute, father executeif(g_argv[1] ! NULL)chdir(g_argv[1]);continue;}//5.forkpid_t id fork();if(id 0){perror(fork);exit(1);}else if(id 0){execvp(g_argv[0], g_argv);exit(1);}int status 0;pid_t ret waitpid(id, status, 0);if(ret 0){printf(exit code:%d - result:%s\n,WEXITSTATUS(status), strerror(WEXITSTATUS(status)));}else{printf(wait fail!\n);exit(1);}}//end whilereturn 0; }5. 函数和进程之间的相似性 exec/exit就像call/return 一个C程序有很多函数组成。一个函数可以调用另外一个函数同时传递给它一些参数。被调用的函数执行一定的操作然后返回一个值。每个函数都有他的局部变量不同的函数通过call/return系统进行通信。 这种通过参数和返回值在拥有私有数据的函数间通信的模式是结构化程序设计的基础。Linux鼓励将这种应用于程 之内的模式扩展到程序之间。 一个C程序可以fork/exec另一个程序并传给它一些参数。这个被调用的程序执行一定的操作然后通过exit(n)来 返回值。调用它的进程可以通过waitret来获取exit的返回值。
http://www.huolong8.cn/news/228757/

相关文章:

  • 百科网站程序郑州网络推广电话
  • 自建网站的缺点做网站需要每年都交钱吗
  • 中英文微信网站开发短视频运营是做什么的
  • 深圳网站设计有哪些济南网站app开发的
  • 宿州网站开发网站使用问题
  • 东莞建设网站企业沟通平台创建网站销售产品
  • 关于网站建设的专家研讨会网络短剧免费观看
  • 网站实现多语言建设工程168网站
  • 湖州市建设培训中心网站注册城乡规划师教材
  • 个人网站可以做百度竞价建设网站服务请示
  • 网站服务器租一个月门店零售管理系统
  • 做医疗类网站有什么需要审核的中国传统美食网页制作素材
  • 适合个人站长的网站有哪些天津在线制作网站
  • 酒仙网技术开发与网站建设方面凡科互动app
  • 合肥网站租房子做民宿在哪个网站
  • qq号码提取网站做直播网站软件
  • 网站数据库查询怎么做展示展厅设计
  • 免费网站风格关键词seo排名公司
  • ppt模板网站开发贵阳网站开发公司
  • 广西贵港网站建设网上房地产官网
  • 做游戏代练网站网站建设一级页面二级页面
  • 文具用品网站设计规划书网站规划步骤有哪些
  • 网站正在建设中 html可信赖的手机网站建设
  • 蜘蛛网是个什么网站辽宁城市建设职业技术学院教育网站
  • 做微信网站的公司无代码开发平台全免费
  • 任何做网站国外产品设计网
  • 网站做线上销售湖北做网站平台哪家好
  • 织梦的手机端网站模板下载地址长沙手机网站设计公司
  • dw做网站需要数据库么留言 wordpress
  • 为您打造高端品牌网站门户网站的含义