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

肇庆网站制作案例用asp做网站需要准备什么软件

肇庆网站制作案例,用asp做网站需要准备什么软件,浅谈高校网站群的建设,2024新冠又来了吗目录 一. 进程信号概述 1.1 生活中的信号 1.2 进程信号 1.3 信号的查看 二. 信号发送的本质 三. 信号产生的四种方式 3.1 按键产生信号 3.2 通过系统接口发送信号 3.2.1 kill -- 向指定进程发送信号 3.2.2 raise -- 当自身发送信号 3.2.3 abort -- 向自身发送进程终止…目录 一. 进程信号概述 1.1 生活中的信号 1.2 进程信号 1.3 信号的查看 二. 信号发送的本质 三. 信号产生的四种方式 3.1 按键产生信号 3.2 通过系统接口发送信号 3.2.1 kill -- 向指定进程发送信号 3.2.2 raise -- 当自身发送信号 3.2.3 abort -- 向自身发送进程终止信号  3.3 软件条件产生信号 3.3.1 管道通信读端关闭 3.3.2 时钟问题 3.4 硬件异常产生信号 3.4.1 除0错误 3.4.2 野指针、越界访问问题 四. Core dump问题 4.1 什么是core dump 4.2 进程退出状态中的core dump标记位 4.3 用core文件调试代码 五. 总结 一. 进程信号概述 1.1 生活中的信号 在生活中信号作为信息通知的一种手段无处不在我们看到信号后需要根据信号的种类来对信号做出特定的反应。如红绿灯、起床闹钟、警铃、电话铃声等都属于信号的范畴。 我们能对信号做出相应的反应是因为我们能够识别信号并且知道对应的处理动作。按照日常经常对于生活中的信号做出以下的特性总结 我们能够认识识别某种信号。即使没有出现特定信号我们也知道信号发出之后应当做出什么反应。 我们可能暂时不对信号进行处理等待合适时机再处理。如果暂时不处理信号我们需要暂时记住信号等待处理。 1.2 进程信号 进程信号与生活中的信号都是用于信息通知的。我们可以这样理解进程信号进程信号是一种信息通知机制由用户或操作系统发送给特定的进程通知进程发生了某事件进程可以稍后处理。 进程对于信号的处理与生活中的信号处理策略本质相同可归为以下三类 按照默认方式处理。红灯停绿灯行铃响后马上起床等自定义处理方式。铃响后再睡十分钟回笼觉然后起床忽视信号即不做任何相应。铃响后让它一直响继续在床上睡觉 同样我们也可以推断出进程信号应用的特性如下 进程有识别信号的能力。每个信号都有对应的编号用于进程识别进程有默认处理信号的方法。由程序员写的代码决定默认处理方法进程可以对信号进行延后处理或根本不处理。用户可以自定义对于特定信号的处理方式。signal函数信号的产生和进程的运行是异步的即产生信号时进程可能在忙自己的事情延后对信号的处理而不是立马处理。 1.3 信号的查看 在Linux系统中通过kill -l指令可以查看系统中所有内置信号的编号与对应名称如图1.1所示。 其中2号信号SIGINT就对应我们经常使用的 Ctrl C 终止进程。 图1.1 信号列表的查看 观察图1.1我们发现信号的最高编号为64没有0号信号没有32、33号信号Liunx总共定义有62个信号。其中 1 ~ 31普通信号。34 ~ 64实时信号。 普通信号用于OS通过正常的运行调度队列调度的进程即进程轮番拿到CPU上去运行每个进程每次在CPU上运行特定的时间片长度然后切换运行进程。  实时信号只用于极少数的生产环境这是OS要求要对某个进程运行完毕才可以从CPU上拿下且进程不应在调度队列中等待调度而是应当立马调度运行。如车载系统接收到刹车指令不可以等待其他进程运行也必须一次完成运行。 通过man 7 signal指令下翻查找我们可以看到每种信号的默认处理方式。 Term -- 进程终止不发生核心转储。Core -- 进程终止发生核心转储。 Ign -- 子进程暂停运行或终止。Cont -- 继续运行进程。Stop -- 暂停运行进程。 图1.2 信号的默认处理方式 二. 信号发送的本质 要理解信号发送的本质首先要理解进程如何保存信号。对信号进行保存需要记录a.哪一种信号b.特定信号是否产生。 这让我们很容易想到位图这种数据结构位图中通过对特定比特位设置0/1值来表示某件事情是否发生或某对象是否存在。进程PCB中存有位图这种数据结构来保存信号每种信号都有其对应的编号每个编号对应位图中的一个bit位1表示产生并保存了某信号0表示没有保存某信号。 如果进程收到了某信号但暂时不对信号做出响应那么就应当将位图中对应的bit位由1置0等待进程做出了响应之后在置回0。 总结信号发送的本质为OS向目标进程写信号 - OS改变进程中记录信号状态的位图中的特点bit位 - 完成信号发送过程。 Crtl C 组合键终止进程最终也是改变进程中位图的bit位值键盘中特定槽位的按键按下键盘驱动就会将按键按下的信息传给OSOS就会将按键信息转换为信号然后发送给进程。 三. 信号产生的四种方式 3.1 按键产生信号 通过组合键的方式可以向进程发送信号如 Ctrl c向前台进程发送2号信号SIGINT。Ctrl \向前台进程发送3号信号SIGQUIT。 其中2号信号的默认处理方式为进程终止不进行核心转储3号信号的默认处理方式为终止进程进程核心转储。本文后面会对核心转储进行讲解 如代码和图3.1所示运行一个间隔1s输出进程pid的进程通过Ctrl C组合键和Ctrl \组合键向这个死循环进程发送信号进程都终止掉了即使没有运行到最后的代码。 代码3.1死循环打印进程pid #include iostream #include unistd.hint main() {while(true){std::cout This is a process, pid: getpid() std::endl;sleep(1);}return 0; } 图3.1 代码3.1运行结果 3.2 通过系统接口发送信号 3.2.1 kill -- 向指定进程发送信号 函数原型int kill(pid_t id, int sig) 头文件#includesys/types.h、#includesignal.h 函数功能向特定进程发送指定信号 返回值发送成功返回0失败发挥-1 编写信号发送程序的源文件kill.cc如代码3.2所示编译生成可执行文件取名为kill在命令行参数中输入 ./kill [id] [sig]即可向指定进程发送特定信号。如图3.2所示通过kill向死循环进程发送8号信号进程被终止掉了。 8号信号SIGFPE浮点数错误常发生于 x/0 的情况除0错误 代码3.2信号发送kill.cc #include iostream #include sys/types.h #include signal.hint main(int argc, char** argv) {// 发送信号必须要有三个命令行参数if(argc ! 3){std::cout 参数个数错误 std::endl;exit(1);}int id atoi(argv[1]); // 获取结束信号进程的idint sig atoi(argv[2]); // 获取信号编号kill(id, sig); // 发信号return 0; } 图3.2 通过kill发送信号 3.2.2 raise -- 当自身发送信号 函数原型int raise(int sig) 头文件#includesignal.h 函数功能向自身发送指定编号的信号 返回值发送成功返回0失败发挥-1 代码3.3在通过fork创建子进程在子进程中循环5次后通过raise向子进程本身发送8号信号父进程阻塞等待子进程退出接收子进程的返回信号并输出到屏幕代码运行结果见图3.3。 代码3.3raise向自身发信号 #include iostream #include sys/types.h #include sys/wait.h #include unistd.h #include signal.hint main() {pid_t id fork();if(id 0){perror(fork);exit(1);}else if(id 0){// 子进程代码int count 0;while(true){std::cout [Child process]# [ getpid() \], count: count std::endl;if(count 5){raise(SIGFPE); //向吱声发送8号信号}sleep(1);}exit(0);}int status 0;pid_t n waitpid(id, status, 0);std::cout signal: (status 0x7F) std::endl;return 0; } 图3.3 代码3.3的运行结果 3.2.3 abort -- 向自身发送进程终止信号  函数原型void abort() 头文件#include stdlib.h 函数功能向自身发送6号终止信号SIGABRT 代码3.3abort向自身发送进程终止信号 #include iostream #include sys/types.h #include sys/wait.h #include unistd.h #include signal.hint main() {pid_t id fork();if(id 0){perror(fork);exit(1);}else if(id 0){// 子进程代码while(true){std::cout [Child process]# pid: getpid() , ppid: getppid() std::endl;abort(); // 向子进程自身发送进程终止信号}exit(0);}int status 0;pid_t n waitpid(id, status, 0);std::cout signal: (status 0x7F) std::endl;return 0; } 3.3 软件条件产生信号 软件条件产生信号就是OS检测到某种软件条件触发或者不满足由OS向指定进程发送信号。如a. 管道通信中读段关闭写端进程退出   b.时钟问题 3.3.1 管道通信读端关闭 管道通信是一种提供访问控制的进程间通信方式一端进程负责写数据写端另一端进程负责读数据读端如果读端关闭那么写端就不再有意义OS会强制终止写端进程。OS终止写端进程的方法就是发送13号信号SIGPIPE。 代码3.4对上述现象进行复现a. 通过fork创建子进程 - b. 父进程读数据子进程写数据 - c. 父子进程进行一段时间的通信 - d.关闭父进程读端管道 - e.父进程阻塞等到子进程退出输出退出状态信息。运行代码可见子进程因接收到了13号SIGPIPE信号而终止退出。 代码3.4管道通信中因软件条件产生信号 #include iostream #include string #include sys/types.h #include sys/wait.h #include fcntl.h #include unistd.hint main() {// 1.创建管道int pipefd[2] {0};int n pipe(pipefd); // 管道创建if(n -1){perror(pipe);exit(1);}// 2.创建子进程pid_t id fork(); // 让子进程写数据 父进程读数据if(id 0){// 子进程发送数据// 3. 关闭不需要的fdclose(pipefd[0]);// 4. 写数据// char send_buffer[1024] {0};std::string message [Child process]# Send message to you;while(true){// 子进程间隔一秒发送数据ssize_t sz write(pipefd[1], message.c_str(), message.size());if(sz 0) sleep(1);else break;}close(pipefd[1]);exit(1);}// 父进程读取数据// 3. 关闭不需要的fdclose(pipefd[1]);// 4. 开始读取数据char read_buffer[1024] {0};int count 0;while(true){ssize_t sz read(pipefd[0], read_buffer, 1024);if(sz 0){read_buffer[sz] \0;std::cout [ getpid() ] read_buffer , count: count std::endl;if(count 5){// 关掉读端// 终止读取死循环close(pipefd[0]);break;}}else break;}// 5. 父进程阻塞等待子进程退出int status 0;waitpid(id, status, 0);std::cout child process exit, write end, exit signal: \ (status 0x7F) std::endl;return 0; } 图3.4 代码3.4的运行结果 3.3.2 时钟问题 首先要了解一下时钟接口函数alarm。 alarm函数 函数原型unsigned int alarm(unsigned int second) 头文件#includeunistd.h 功能调用时钟函数second秒后向进程发送14号SIGALRM信号在倒计时期间进程继续运行不受影响。 返回值如果之前有alarm函数被调用返回上一个时钟倒计时还有几秒如果之前没有alarm函数被调用返回0。 代码3.5为算力评估函数通过时钟函数自定义处理14号SIGALRM信号的方法计算1s内CPU能够进行多少次的操作在自定义信号处理方法中输出。 代码3.5通过alarm函数进行算力评估 #include iostream #include unistd.h #include signal.huint64_t count 0;void handler(int sig) // 自定义信号处理函数 {std::cout count end, final count: count std::endl;exit(0); }int main() {signal(SIGALRM, handler);alarm(1); // 倒计时1秒while(true) count;return 0; } 图3.5 代码3.5的运行结果 3.4 硬件异常产生信号 硬件异常被硬件以某种方式记录通常为寄存器中的状态标记信息由OS检测到并产生信号发送给进程。比如除0错误被CPU检查并记录OS检测到并产生SIGFPE信号发送给进程再比如野指针、越界访问内存的问题MMU检测到了非法访问由硬件记录异常状态OS检测到后发送SIGSEGV信号给进程。 Linux中越界访问、野指针等问题通常都被记录为段错误Segmentation fault对应11号SIGSEGV信号。 3.4.1 除0错误 代码3.6自定义了对SIGFPE信号的处理方法handler_signal出现异常程序不会退出终止在主函数中先人为写出除0错误然后while(true)死循环。 按照我们的一般认知进程在接收到信号后只会执行一次对应的自定义处理动作但是如图3.6所示handler_signal函数在不断地被运行这是为什么更加奇怪的是如果将代码中发生/0错误的部分注释掉通过命令行kill -8的方法人为向进程发送8号信号handler_signal就只会被执行一次 代码3.6除0错误引发硬件异常 #include iostream #include signal.h #include unistd.hvoid handler_signal(int sig) {std::cout recieve a signal: sig std::endl;sleep(1); }int main() {signal(SIGFPE, handler_signal);int a 10;int b a/0;while(true) {}return 0; } 图3.6 代码3.6运行结果 自定义handler_signal后除零错误产生的现象 如果代码本身发生除0错误handler_signal被一次次执行。如果人为通过kill -8发送信号handler_signal只被执行一次。  产生这种现象的原因就在于代码本身产生的除0错误为硬件异常而人为kill -8发送信号不经由硬件直接被OS处理后将信号发送给进程。 我们可以以如下的方式理解硬件产生的除0异常和上面的奇怪现象 计算是由硬件CPU来完成的CPU会赋值进行溢出检查。CPU的寄存器中会记录有状态信息其中就包括溢出标志位如果出现除0错误或其他溢出问题CPU寄存器中的溢出标志位就会被置1OS会在计算完成时对CPU寄存器中的状态信息进行检测如果检测到溢出标记位为1OS就会向进程发送8号SIGFPE信号。进程接收到了8号异常信号后并不一定会退出如果自定义了处理函数。若进程不退出OS就会对CPU寄存器中的状态信息进行轮巡检测溢出标记在除零错误发生后并没有被置回0OS就会不断检测到异常信息进而不断向进程发送SIGFPE信号进而一直在调用handler_signal处理信号。通过kill -8 发送信号是一种纯软件行为并没有经过硬件没有设置过CPU中的标记位在CPU轮巡检测的过程中也就不会被不断检测出异常。 3.4.2 野指针、越界访问问题 当某个进程需要访问物理内存资源时需要先拿到进程地址空间的虚拟地址再通过 页表 MMU(Memery Manager Unit内存管理模块) 映射到物理内存的方式来访问。 我们获取认为页表映射是OS所进行的软件行为其实不是试想一下通过页表映射物理内存是进程运行过程中大量、高频执行的操作如果有OS来进行这一操作就严重延缓了计算机设备的整机效率。 实际的情况是OS将页表和虚拟地址信息以二进制的方式写入到硬件中去通过虚拟地址  页表 映射物理内存的方法是由硬件来完成的那么出现越界、野指针等问题也理应属于硬件异常。 我们可以按照以下方式理解野指针、越界访问的问题 进程必须要通过地址来访问物理内存而现代计算机使用的都是虚拟地址。虚拟地址需要通过 页表 MMUMemery Manager Unit硬件来完成虚拟地址到实际地址的转换。在不考虑编译器优化的情况下如果出现野指针、越界访问等问题MMU一定会报错。页表 MMU映射物理内存地址是硬件层面的操作出错当然也属于硬件异常硬件会对相应的寄存器标志位进行设置供OS进行轮巡检测。 出现野指针、越界访问等问题在Linux中属于段错误OS会向进程发送11号SIGSEGV信号。 代码3.7模拟了野指针问题产生的硬件异常行为代码运行结果与3.6一致都是不间断执行信号处理函数signal_handler因为OS在对硬件寄存器中的信息进行轮巡检测。 代码3.7野指针问题引发硬件异常 #include iostream #include signal.h #include unistd.hvoid handler_signal(int sig) {std::cout recieve a signal: sig std::endl;sleep(1); }int main() {signal(SIGSEGV, handler_signal);int* pa nullptr;*pa 10;while(true) {}return 0; } 图3.7 代码3.7的运行结果 四. Core dump问题 4.1 什么是core dump 通过man 7 signal查看每种信号对应的默认处理方法如果为Core那么默认会产生Core文件OS会将当前进程内存中的核心数据全部保存到Core文件中Core文件是用来调试的。 如3号SIGQUIT信号、8号SIGFPE信号、11号SIGSEGV信号默认触发响应都会产生Core文件而2号SIGINT、9号SIGKILL信号默认不会产生Core文件。 一般而言生产环境、云服务器的core dump功能都是关闭的如果想要在响应信号的时候产生core文件还必须保证core dump功能打开。 ulimit -a 指令可用于查看core dump功能是否打开如果输出结果的第一行core file size为0那么表示core dump功能没有打开。ulimit -c [size] 指令 -- 通过指定file文件的大小非0来打开core file功能。 图4.1 查看和开启core dump 4.2 进程退出状态中的core dump标记位 通过wait/waitpid函数可以实现父进程对子进程的等待wait/waitpid函数都可以接收int*类型的输出型参数用于记录子进程的退出状态我们称之为int statusstatus在进程正常退出和异常退出的状态下如图4.2所示根据退出状态和status比特位的划分对应子进程退出状态。 图4.2 进程退出状态status的比特位使用情况 代码4.1创建进行死循环的子进程并且waitpid阻塞等待子进程退出输出信号编号和core dump标记位在代码运行起来后通过在命令行中向子进程发送3号信号(kill -3 [pid])强制子进程终止并在进程终止后通过ll指令查看当前路径下的文件及属性可以看到生成的core文件。 代码4.1子进程信号编号和core dump标志的获取 #include iostream #include sys/types.h #include sys/wait.h #include unistd.hint main() {// 1. 创建子进程pid_t id fork(); if(id 0){perror(fork);exit(1);}else if(id 0){// 2. 子进程代码while(true){std::cout [Child process]# pid: getpid() , getppid: getppid() std::endl;sleep(1);}exit(0);}// 3. 父进程阻塞等待子进程并获取退出状态int status 0;waitpid(id, status, 0);//4. 检查子进程退出状态if(WIFEXITED(status)){std::cout 子进程正常终止 std::endl;std::cout exit code: WEXITSTATUS(status) std::endl;}else{std::cout 子进程被信号所杀 std::endl;std::cout signal: (status 0x7F) , core dump: ((status 7) 1) std::endl;}return 0; } 图4.3 代码4.1的运行结果 4.3 用core文件调试代码 Linux下的gcc/g编译器默认采用Release版本发布可执行程序若要对代码进行调试就需要Debug版本的可执行程序这就需要在使用gcc/g编译源文件的时候添加-g选项。 代码4.2人为制造除0错误这样就会有8号信号发给进程8号信号默认会产生core文件。编译代码生成Debug版本的可执行程序。使用gdb启动调试之后在命令行中输入指令core-file [core文件名]就会显示出出现异常的行数以及其他的错误信息。 gdb指令core-file [core文件名] -- 引入core文件调试代码定位出错位置查看错误信息 代码4.2出现异常并生成Core文件的测试代码 #include iostream #include unistd.hint main() {int a 10;int b a/0;sleep(1);std::cout run here std::endl;return 0; } 图4.4 代码4.3的运行和调试结果 五. 总结 进程信号用于向进程发送信息通知进场某件事情的发生进程咱叔不响应信号等待合适的时机再进行响应。进程处理信号的方式和分为三种a. 按照默认方式响应  b.按照用户自定义的方式响应  c.直接忽略信号不做处理。如果进程暂时不响应信号则需要对进行进行暂时保存。信号保存需要存储信号编号以及它是否产生Linux中使用位图保存信号而位图存于每个进程的PCB中。发送信号的本质就是更改位图中对应的二进制位。信号可以通过四种方式产生1.按键  2.系统接口调用  3.软件行为  4.硬件异常如果某种信号的默认处理方式会产生core文件而且系统的Core dump功能处于开启状态那么进程在接收到这些信号后会生成core文件core文件用于对代码的调试可以帮助快速定代码中出现异常的位置以及错误信息。
http://www.yayakq.cn/news/4104/

相关文章:

  • 百度搜索到自己的网站pc端ui设计
  • 哪些网站可以免费看剧企业网站静态模板下载
  • 做头像网站有哪些福州网站排名优化
  • 漯河有没有做网站的域名对seo的影响
  • 编写网站的软件安平做网站做推广电话
  • 买网站注册人数wordpress完整虚拟资源下载类源码
  • 网站建设的基本流程是什么江苏省现代化示范校建设网站
  • 网站建设什么科目wordpress后台入口
  • 网站开发学什么好wordpress 获取文章链接
  • 青岛外贸网站推广收费小说网站怎么做
  • 网站分类模板网站域名解析ip
  • 保定网站建设兼职怀化建设局网站
  • 广告推销网站东莞企业网站多少钱
  • html移动网站开发国外 素材 网站
  • 个人网站备案怎么做免费wordpress
  • python搭建网站自己做的网页怎么发布
  • 网站建设意味着什么网站建设整体情况介绍
  • 网站怎么做构成网站开发前端模板
  • 潍坊 区网站建设国内有名室内设计公司
  • 快速网站备案中国购物网站有哪些
  • 优设网站怎么下载服务好的普通网站建设
  • 网站整体建设方案论文在什么网站可以做推广
  • 国外好玩的网站网站顶部轮播怎么做
  • 临沂做网站的2022年新闻热点事件
  • 网站推广四个阶段wordpress 全屏主题
  • 婚纱摄影网站定制seo优化网站建设哪家好
  • 网站建设时间计划图域名怎么绑定自己网站
  • 门户网站域名杭州建设工程协会
  • 企业网站托管费用现在 做网站 最流行
  • 网站后台管理怎么进电脑iis做网站