Linux之进程控制
一.进程创建
1.1 fork函数
我们创建进程的方式有./xxx和fork()两种
在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。
#include <unistd.h>
pid_t fork(void);
返回值:自进程中返回0,父进程返回子进程id,出错返回-1
进程调用fork,当控制转移到内核中的fork代码后,内核做:
1.分配新的内存块和内核数据结构给子进程
2.将父进程部分数据结构内容拷贝至子进程
3.添加子进程到系统进程列表当中
4.fork返回,开始调度器调度
fork之前父进程独立执行,fork之后,父子两个执行流分别执行。注意,fork之后,谁先执行完全由调度器决定。
1.2.fork返回值
1.子进程返回0。
2.父进程返回的是子进程的pid。
1.3.写时拷贝
当子进程被创建出来,子进程中的数据和代码都是和父进程共用一份,也就是说父子进程的页表中的代码和数据都是只读权限,当子进程想要修改数据的时候,就会发生缺页中断,也就是子进程修改数据的操作被暂停,然后操作系统开辟新的空间,将数据的数值拷贝进该空间中,修改父子进程对于页表中该数据的权限为可读可写,将页表的数据地址指向该新开辟的空间,操作系统完成这些操作之后,子进程修改数据的操作继续进行,通过页表完成数据修改。
1.4 fork常规用法
1. 一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。
2. 一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。
1.5 fork调用失败的原因
系统中有太多的进程
实际用户的进程数超过了限制
二.进程终止
2.1 进程退出场景
1. 代码运行完毕,结果正确
2. 代码运行完毕,结果不正确
3. 代码异常终止
main函数的return值是进程的退出码
通过echo $?可以输出最近一次进程退出时的退出码,可以看到main函数的return值是进程的退出码
代码执行完毕,结果正确,只有一种可能,所以返回0,但是代码运行完毕,结果不正确,却有很多种可能性,在Linux中,我们查看到有134种错误的返回
当进程异常终止的时候就相当于程序运行崩溃,它的退出码是没有意义的,程序正常运行结束之后的退出码才有意义
我们除以0值为例子
它的程序运行会崩溃,退出码没有意义
2.2 进程常用退出方法
正常终止(可以通过echo $? 查看进程退出码):
1. 从main返回:
main函数return,代表进程退出!!其他的非main函数呢??代表的是函数返回
2. 调用exit:
exit在任意地方调用,都代表终止进程,参数是退出码!它跟main返回一样,都会刷新输出缓冲区
在4s之后,才刷新输出缓冲区,打印输出hello world
3. _exit:
终止进程,但强制终止进程,没有进行进程的后续收尾工作,比如刷新缓冲区(用户级缓冲区)!!
进程退出,在操作系统层面做了什么呢?
在系统层面,少了一个进程:释放进程控制块,释放进程地址空间,释放页表和各种映射关系,还有代码和数据也都会被释放掉!
三.进程等待
子进程被创建出来,是为了完成父进程的某些任务的,但是子进程和父进程何时结束,这是未知的,所以父进程fork之后,需要通过wait()/waitpid()等待子进程退出。
为什么要让父进程等待呢?
1.通过获取子进程退出的信息,能够得知子进程执行结果
2.可以保证:时序问题,子进程先退出,父进程后退出
3.进程退出的时候会先进入僵尸状态,会造成内存泄漏问题,需要通过父进程wait,释放该子进程占用的资源
两个等待函数:wait()和waitpid()
wait(int* status):
查看Linux进程的相关信息的指令:
while :; do ps axj | head -1 && ps axj | grep myproc | grep -v grep; sleep 1; echo "#####################################";done;
子进程被创建:
5秒后,子进程终止退出,进入僵尸状态:
10秒后,父进程回收子进程,父进程继续执行程序:
再过5秒父进程结束
上面这段代码是为了实现在子进程退出之后,成为僵尸进程,然后父进程继续执行程序,回收子进程的信息
waitpid(pid_t pid, int* status, int options):
执行结果跟wait()一样
在上面的代码中waitpid的第一个参数是要等待的那一个进程的pid,如果值为-1,表示等待任意一个子进程
第二个参数就是
我们通过上面的代码知道,当子进程退出码是0的时候,父进程从waitpid获取到的状态码是0,而子进程退出码是10的时候,父进程从waitpid获取到的状态码是2556;也就是说,父进程拿到什么status结果,一定和子进程如何退出是强相关的,而我们刚刚知道进程退出时,有三种结果,那么不难得出最终父进程一定会通过status得到子进程执行的结果,
如果程序代码运行完毕,结果与否,进程就会返回退出码给父进程(通过return / exit),如果代码异常终止,本质上时这个进程因为异常问题,导致自己收到某种信号
这个status是int类型,有32位,只使用低16位
父进程首先识别status的低7位终止信号是否为0,如果为0,表示正常退出,否则异常退出,若为0,继续识别高8位是否为0,为0结果正确
验证:
tips:退出码=(status>>8)&0xFF,退出信号=status&0x7F
代码运行完成 ,且结果正确的情况:
代码运行完成 ,结果不正确的情况:
代码运行过程中,收到信号异常退出的情况:
判断status的另外一种操作:
理解一下waitpid():
waitpid()处在用户层和操作系统之间,是操作系统提供给用户层的接口,在操作系统中,僵尸子进程的PCB中保存着进程退出时的退出数据,里面包括退出码和退出信号,父进程回收该子进程的时候,就会将status与退出码和退出信号进行位与运算,获取到带有子进程退出时的退出码和退出信号信息的退出状态status,然后将status返回给用户
在WaitPid()的第三个参数中,0表示阻塞等待,WNOHANG表示非阻塞等待
阻塞等待:父进程等待子进程退出,子进程不退出,父进程就会一直等待,直到子进程退出。
阻塞了是不是意味着父进程不被调度执行了呢?
不会,父进程会被链入到等待队列中,从R状态变为S状态,不会被CPU调度执行,直到子进程退出,父进程从等待队列中取出,然后S状态变为R状态,被插入运行队列中,被CPU继续调度执行
阻寒的本质: 其实是进程的PCB被放入了等待队列,并将进程的状态改为S状态,返回的本质: 进程的PCB从等待队列拿到R队列,从而被CPU调度
非阻塞等待:父进程轮询检测子进程是否退出,如果子进程退出,查看waitpid检测成功与否,如果子进程没有退出,就继续轮询检测子进程是否退出
测试代码:
执行结果:
子进程在执行代码得时候,父进程轮询等待,期间每轮询一次,父进程在做自己的事情。
四.程序替换
4.1为什么要进行程序替换??
如果我们想让一个子进程执行一个全新的程序的时候,我们就需要程序替换
4.2 什么是程序替换?原理是什么?
进程不变,仅仅替换当前进程得代码和数据得技术叫做进程得程序替换
程序本质上就是存放在磁盘中的文件,这些文件=程序代码+程序数据,操作系统将该文件中的代码和数据替换到已存在的进程中的代码和数据,这一过程我们称之为程序替换!!他并没有创建新的进程,只是老进程的壳子(进程地址空间,PCB,页表)不变,把新程序的代码和数据替换进物理内存就可以了
在上面的代码中,程序替换之后的的代码是不会执行的
程序替换的本质就是把程序的进程代码+数据,加载进特定进程的上下文中!!C/C++程序要运行,必须得先加载到内存中!那么怎么加载呢?通过exce*程序替换函数。
在上面的代码中,由于进程具有独立性,以及写时拷贝的存在,虽然父子代码是共享的,但是进程程序替换会更改代码区的代码,然后发生写时拷贝
执行结果:
进程的程序替换的使用?
1.现象
2.fork()
3.exec*返回值
4.3 各个程序替换函数的基本使用
替换函数:
其实有六种以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 execve(const char *path, char *const argv[], char *const envp[]);
函数解释:
这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
如果调用出错则返回-1
所以exec函数只有出错的返回值而没有成功的返回值。
命令理解:
l(list) : 表示参数采用列表
v(vector) : 参数用数组
p(path) : 有p自动搜索环境变量PATH
e(env) : 表示自己维护环境变量
1.execl(const char* path, const char* arg, ...);
在execl中,第一个参数是你的要执行的目标程序的全路径(所在路径/文件名)
第二个参数往后就是要执行的目标程序,在命令行上怎么写的这里的参数就怎么一个一个的传递进去,最后以NULL结尾
等价于
2.int execlp(const char *file, const char *arg, ...);
在execlp中,第一个参数是你的要执行的目标程序的文件名(不带路径,会自动去环境变量PATH找该文件)
第二个参数往后就是要执行的目标程序,在命令行上怎么写的这里的参数就怎么一个一个的传递进去,最后以NULL结尾
3.int execv(const char *path, char *const argv[]);
在execv中,第一个参数是你的要执行的目标程序的全路径(所在路径/文件名)
第二个参数是一个命令行参数数组,把命令行上写的那些参数一个一个写进这个数组里面
4.int execvp(const char *file, char *const argv[]);
在execv中,第一个参数是你的要执行的目标程序的文件名(不带路径,会自动去环境变量PATH找该文件)
第二个参数是一个命令行参数数组,把命令行上写的那些参数一个一个写进这个数组里面
5.int execle(const char *path, const char *arg, ...,char *const envp[]);
在execlp中,第一个参数是你的要执行的目标程序的文件名(不带路径,会自动去环境变量PATH找该文件)
第二个参数往后就是要执行的目标程序,在命令行上怎么写的这里的参数就怎么一个一个的传递进去,最后以NULL结尾
第三个参数是给该程序赋予环境变量
让myproc的子进程执行程序myexe,在myproc的子进程中使用execle函数将指定的环境变量给程序myexe,然后程序myexe打印出来
6.int execve(const char *path, char *const argv[], char *const envp[]);
在execlp中,第一个参数是你的要执行的目标程序的文件名(不带路径,会自动去环境变量PATH找该文件)
第二个参数是一个命令行参数数组,把命令行上写的那些参数一个一个写进这个数组里面
第三个参数是给该程序赋予环境变量
有了这些函数,我们就可以是在C/C++中调用其他编程语言的程序了!!
所有的接口看起来是没有太大差别的,只有一个参数的不同!!
为什么会有这么多接口,是为了满足不同的应用场景的
六个函数接口的关系:
execve是系统调用函数其他函数都是在该函数的基础上进行的封装
4.4 利用程序替换实现shell命令解释器
在Linux中shell命令行解释器本质上就是一个进程,它的名字叫bash,我们在命令行中执行的程序的父进程就是它,它通过解析我们在命令行上输入的命令字符串,然后去环境变量PATH中找到相应的命令程序,创建子进程来执行该命令程序,最后将结果打印出来。
上面说的是执行第三方命令的时候就会这样操作,但是执行内建命令的时候,就不需要创建子进程去执行命令,而是直接shell进程调用命令函数来执行内建命令
tips:什么是内建命令,什么是第三方命令?
第三方命令:
外部命令,有时候也被称为文件系统命令,是存在于bash shell之外的程序。外部命令程序通常位于/bin、/usr/bin、/sbin或/usr/sbin中。外部命令需要使用子进程来执行。受到环境变量的影响
内建命令:
它是shell的一部分,执行内建命令等于调用bash shell程序的一个程序,它不会受到环境变量的影响,内建命令比外部命令,效率更高,执行更快,执行内建命令相当于调用当前 Shell 进程的一个函数。比如cd、exit 这些是内部命令,本质是函数调用,可以直接使用,内建命令并不是某个外部程序,而是bash shell该程序的组成部分,只要在 bash shell 中就可以运行这个命令。
代码:
1 #include<stdlib.h>2 #include<iostream>3 #include<unistd.h>4 #include<sys/wait.h>5 #include<sys/types.h>6 #include<string.h>7 #define NUM 1288 #define CMD_NUM 649 10 int main()11 {12 char command[NUM];//命令字符串13 while(1)14 {15 char* argv[CMD_NUM] = {NULL};16 //1.打印提示符17 command[0] = 0;//清空字符串;18 std::cout << "[who@myhostname mysir]# ";19 fflush(stdout);20 //sleep(10);21 22 //2.获取命令字符串23 fgets(command, NUM, stdin);//从命令行获取命令字符串24 command[strlen(command) - 1] = 0;25 //std::cout << "command is: " << command << std::endl;26 27 //3.解析命令字符串,char* argv[];28 int cnt = 0;29 argv[0] = strtok(command, " ");30 cnt++;31 while(argv[cnt] = strtok(NULL, " "))32 {33 cnt++;34 }35 36 //4.执行内建命令,相当于调用一个函数 37 if(strcmp(argv[0], "cd"))38 {39 if(argv[1] != NULL) chdir(argv[1]);40 continue;41 }42 43 //执行第三方命令44 if(fork() == 0)//创建子进程执行第三方命令45 {46 execvp(argv[0], argv);47 //td::cout << "执行命令失败" << std::endl;48 exit(1);49 }50 waitpid(-1, NULL, 0);51 }52 return 0;53 }
相关文章:
Linux之进程控制
一.进程创建 1.1 fork函数 我们创建进程的方式有./xxx和fork()两种 在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。 #include <unistd.h> pid_t fork(void); 返回值:自进程…...
SpringBoot社区版专业版带你配置热部署
💟💟前言 友友们大家好,我是你们的小王同学😗😗 今天给大家打来的是 SpringBoot社区版专业版带你配置热部署 希望能给大家带来有用的知识 觉得小王写的不错的话麻烦动动小手 点赞👍 收藏⭐ 评论…...
影响AFE采样精度的因素有哪些?
**AFE(Analog Front End)**是模拟前端电路的缩写,它是模拟信号传感器和数字信号处理器之间的连接点。AFE采样精度是指模拟信号被数字化后的准确度,对于很多电子设备来说,这是一个至关重要的性能指标。本文将介绍影响AF…...
mysqlbackup备份报error:redo log was overwritten
问题原因 备份时redo log被覆盖 解决方案 方法1:增加innodb_log_file_size、innodb_log_files_in_group大小,需要重启数据库 vi my.cnf innodb_log_file_size 2G innodb_log_files_in_group 4 方法2: 动态配置redo log archive,不需要重启…...
Android支持库
# 支持库 注意:Android 9.0(API 级别 28)发布后,新版支持库 AndroidX 也随之诞生,它属于 Jetpack。除了现有的支持库,AndroidX 库还包含最新的 Jetpack 组件。 您可以继续使用此支持库以往的工件(这里指的是版本 27 及更早版本,且已打包为 android.support.*)在 Googl…...
Vue:filters过滤器
日期、时间格式化是Vue前端项目中较为常遇到的一个需求点,此处,围绕Vue的过滤器来介绍如何更为优雅的解决此类需求。 过滤器filters使用注意点 Vue允许开发者自定义过滤器,可以实现一些常见的文本格式化等需求。 使用时要注意的点在于&#…...
Windows环境下安装和配置Gradle
1. 概述 Gradle是Google公司基于JVM开发的一款项目构建工具,支持Maven,JCenter多种第三方仓库,支持传递性依赖管理,使用更加简洁和支持多种语言的build脚步文件,更多详情可以参阅Gradle官网 2. 下载 由于Gradle与S…...
数据结构时间空间复杂度笔记
🕺作者: 迷茫的启明星 本篇内容:数据结构时间空间复杂度笔记 😘欢迎关注:👍点赞🙌收藏✍️留言 🏇家人们,码字不易,你的👍点赞🙌收藏❤…...
基于注意力的知识蒸馏Attention Transfer原理与代码解析
paper:Paying More Attention to Attention: Improving the Performance of Convolutional Neural Networks via Attention Transfercode:https://github.com/megvii-research/mdistiller/blob/master/mdistiller/distillers/AT.py背景一个流行的假设是存…...
利尔达在北交所上市:总市值突破29亿元,叶文光为董事长
2月17日,利尔达科技集团股份有限公司(下称“利尔达”,BJ:832149)在北京证券交易所上市。本次上市,利尔达的发行价格为5.00元/股,发行数量为1980万股,发行市盈率为12.29倍,募资总额为…...
C#操作字符串方法 [万余字总结 · 详细]
C#操作字符串方法总结C#常用字符串函数大全C#常用字符串操作方法C#操作字符串方法总结C#常用字符串函数大全 Compare 比较字符串的内容,考虑文化背景(场所),确定某些字符是否相等 CompareOrdinal 与Compare一样,但不考虑文化背景 Format 格…...
极兔一面:10亿级ES海量搜索狂飙10倍,该怎么办?
背景说明: ES高性能全文索引,如果不会用,或者没有用过,在面试中,会非常吃亏。 所以ES的实操和底层原理,大家要好好准备。 另外,ES调优是一个非常、非常核心的面试知识点,大家要非…...
【Mysql基础 —— SQL语句(一)】
文章目录概述使用启动/停止mysql服务连接mysql客户端数据模型SQLSQL语句分类DDL数据库操作表操作查询创建数据类型修改删除DML添加数据修改数据删除数据DQL基础查询条件查询聚合函数分组查询排序查询分页查询执行顺序DCL管理用户权限控制概述 数据库(Database&#…...
华为OD机试 - 新员工座位安排系统(Python) | 机试题算法思路
最近更新的博客 华为OD机试 - 招聘(Python) | 备考思路,刷题要点,答疑 【新解法】华为OD机试 - 五键键盘 | 备考思路,刷题要点,答疑 【新解法】华为OD机试 - 热点网络统计 | 备考思路,刷题要点,答疑 【新解法】华为OD机试 - 路灯照明 | 备考思路,刷题要点,答疑 【新解…...
MySQL - 介绍
前言 本篇介绍认识MySQL,重装mysql操作 如有错误,请在评论区指正,让我们一起交流,共同进步! 本文开始 1.什么是数据库? 数据库: 一种通过SQL语言操作管理数据的软件; 重装数据库的卸载数据库步骤 : ① 停止MySQL服…...
ChatGPT国内镜像站初体验:聊天、Python代码生成等
ChatGPT国内镜像站初体验,聊天、Python代码生成。 (本文获得CSDN质量评分【92】)【学习的细节是欢悦的历程】Python 官网:https://www.python.org/ Free:大咖免费“圣经”教程《 python 完全自学教程》,不仅仅是基础那么简单………...
SAP数据导入工具(LSMW) 超级详细教程(批量导入内部订单)
目录 第一步:记录批导步骤编辑数据源对应字段 第二步:维护数据源 第三步:维护数据源对应字段(重要) 第四步:维护数据源关系。 第五步:维护数据源与导入字段的对应关系。 第六步࿰…...
第9天-商品服务(电商核心概念,属性分组开发及分类和品牌的级联更新)
1.电商核心概念 1.1.SPU与SKU SPU:Standard Product Unit(标准化产品单元) 是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个 产品的特性。 决定商品属性的值 SKU:Stock…...
动漫人物眼睛画法
本期的动漫绘画课程教大家来学习动漫人物眼睛画法,结合板绘软件从草稿开始一步步教你画出动漫人物眼睛,不用报动漫培训班也能学会,快来跟着本期的动漫人物眼睛画法教程试试吧! 动漫人物眼睛画法步骤教程: 注意&#x…...
张晨光-JAVA零基础保姆式JDBC技术教程
JDBC文档 JDBC概述 JDBC概述 Java DataBase Connectivity Java 数据库连接技术 JDBC的作用 通过Java语言操作数据库,操作表中的数据 SUN公司为**了简化、**统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC JDBC的本质 是官方…...
华为OD机试 - 最多提取子串数目(Python)
最多提取子串数目 题目 给定由 [a-z] 26 个英文小写字母组成的字符串 A 和 B,其中 A 中可能存在重复字母,B 中不会存在重复字母 现从字符串 A 中按规则挑选一些字母,可以组成字符串 B。 挑选规则如下: 1) 同一个位置的字母只能被挑选一次 2) 被挑选字母的相对先后顺序不…...
LeetCode-1237. 找出给定方程的正整数解【双指针,二分查找】
LeetCode-1237. 找出给定方程的正整数解【双指针,二分查找】题目描述:解题思路一:双指针。首先我们不管f是什么,即function_id等于什么不管。但是我们可以调用customfunction中的f函数,然后我们遍历x,y(1 < x, y &l…...
广度优先搜索算法 - 迷宫找路
广度优先搜索算法1 思考问题1.1 这个迷宫需不需要指定入口和出口?2 先粗略实现2.1 源码2.2 源码解释3 优化代码3.1 优化读取文件部分3.2 增加错误处理4 再优化-让程序变得更加灵活4.1 用户外部可以循环输入入口和出口5 完整代码这是一个提问者的提出的问题ÿ…...
泡脚材料简记
文章目录一般条件中药包(药粉)泡脚丸中药包(药材)艾叶生姜益母草藏红花食盐花椒白醋柠檬藿香泡脚私方紫苏叶、白术、白芍、黄芪、青皮、柴胡、夜交藤、丹参、当归,每种各10g艾叶、花椒、肉桂、桂枝、红花干姜30克、小茴…...
【计算机网络】因特网概述
文章目录因特网概述网络、互联网和因特网互联网历史与ISP标准化与RFC因特网的组成三种交换方式电路交换分组交换和报文交换三种交换方式的对比与总结计算机网络的定义和分类计算机网络的定义计算机网络的分类计算机网络的性能指标速率带宽吞吐量时延时延带宽积往返时间利用率丢…...
STC单片机 VS/HX1838红外接收和发送实验
STC单片机 VS/HX1838红外接收和发送实验 📌相关篇《STC单片机获取红外解码从串口输出》🔨所使用的红外接收头VS1838 📋VS1838引脚定义🌿5MM发射头,940nm红外发射二极管 红外遥控发射头。(外观看起来和普通的发光二极管没有什么差异,购买时需要注意确认)。 🔰采用的…...
前端开发常用案例(一)
前端开发常用案例1.实现三角形百度热榜样式分页效果小米商城自动轮播图效果二级下拉菜单效果时间轴效果展示音乐排行榜效果鼠标移入文字加载动画鼠标悬停缩放效果1.实现三角形 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8…...
Linux 日志查找常用命令
1.1 cat、zcat cat -n app.log | grep "error":查询日志中含有某个关键字error的信息,显示行号。 cat -n app.log | grep "error" --color:查询日志中含有某个关键字error的信息,显示行号,带颜色…...
CleanMyMac4.12.5最新版安装下载教程
告别硬盘空间不足,让您的Mac极速如新CleanMyMac是一款强大的 Mac 清理、加速工具和健康卫士,让您的 Mac 加快启动速度。CleanMyMac是一款专业的Mac清理软件,可智能清理mac磁盘垃圾和多余语言安装包,快速释放电脑内存,轻…...
RFID射频识别技术(四) RFID高频电路基础|课堂笔记|10月11日
2022年10月11日 week7 目录 第四讲: RFID高频电路基础 一、RLC(串联)电路的阻抗...
政府网站系统统一/厦门seo公司到1火星
关键字:身份证识别、二代证识别、二代身份证识别、OCR、Android身份证识别、IOS身份证识别、身份证扫描识别、身份证拍照识别 应用背景 随着智能终端(智能手机及平板电脑)及移动 通信(3G)的发展,原来运行在…...
好网站/得物app的网络营销分析论文
作者:satuen在单板计算机的世界里,毫无疑问,树莓派必有一席之地。从性能、大小、性价比及生态发展各方面综合来说,树莓派可以称得上是王者。这样说是有理由的。在林林总总的SBC产品中,有些产品鼓吹性能、有些产品宣扬易…...
wordpress4.0.x 下载/搜索引擎有哪些?
来源:ConsenSys由 ConsenSys 推出的 Infura 提供了世界领先的区块链开发工具套件,其用户基数已经在不到一年的时间里增加了 250%,从 10 万人增加到 35 万人。Infura 平台提供 API 服务,可以快速连接到以太坊和其他网络 (如 IPFS、…...
企业电子商务网站优化方案/seo自学网免费
模块化编程编辑 模块化编程是一种软件设计技术,它强调将程序的功能分为独立的,可互换的模块,以使每个模块都包含执行所需功能的一个方面所必需的一切。 模块接口表示该模块提供和需要的元素。接口中定义的元素可由其他模块检测。该实现包含与…...
杭州网站制作/榆林百度seo
自然界的颜色千变万化,为了给颜色一个量化的衡量标准,就需要建立色彩空间模型来描述各种各样的颜色,由于人对色彩的感知是一个复杂的生理和心理联合作用 的过程,所以在不同的应用领域中为了更好更准确的满足各自的需求,就出现了各种各样的色彩空间模型来量化的描述颜色。我…...
品牌网站建设解决/外贸网站模板
危险函数 mixed eval (string $code) 把字符串作为PHP代码执行bool assert (mixed $assertion [,string $description]) 替代eval函数。相同功能。mixed preg_replace(mixed $pattern,mixed $replacement,mixed $subject[,int $limit-1 [,int&$count]])/e修正符使preg_rep…...