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

个人做网站还是公众号赚钱好海南短视频搜索seo哪家实惠

个人做网站还是公众号赚钱好,海南短视频搜索seo哪家实惠,设计类网站建设规划书,网站开发前端和后端的区别目录 前言#xff1a; 一、进程创建 1.1 fork函数 1.2 fork函数返回值 1.3 写时拷贝 1.4 fork的常规用法 二、进程终止 2.1、退出码 2.2、进程终止的方式 三、进程等待 3.1、等待的必要性 3.2 wait与waitpid wait waitpid status的提取问题 四、重谈进程退出 …目录 前言 一、进程创建 1.1 fork函数 1.2 fork函数返回值 1.3 写时拷贝 1.4 fork的常规用法 二、进程终止  2.1、退出码 2.2、进程终止的方式 三、进程等待 3.1、等待的必要性 3.2 wait与waitpid wait waitpid status的提取问题  四、重谈进程退出 总结 前言 前面关于进程的五篇博客主要给大家讲解的是一些进程的相关概念从本篇开始将为大家带来有关我们进程控制的内容。 我们怎么在我们的代码中控制、管理我们的进程呢进程有哪些基本的用图呢 希望通过本篇博客能够给大家解决这些疑惑。 一、进程创建 1.1 fork函数 在linux系统中fork是一个十分重要的函数它从一个已经存在的进程中创建一个新的进程。这个进度进程为原进程的子进程原进程为父进程。 进程调用fork当控制转移到内核中的fork代码后内核会做四件事情 1、分配新的内存块与内核数据结构PCB给子进程 2、将父进程部分数据结构内容拷贝到子进程 3、添加子进程到系统进程列表中 4、fork返回开始调度器调度 当一个进程调用fork之后就有两个二进制代码相同的进程。而且他们都运行到了相同的地方复制了指令指针寄存器EIP/RIP相当于程序执行的书签。但每个进程都将可以开始他们自己的旅程。 譬如我们有以下代码 #includestdio.h #includeunistd.h #includesys/types.hint main() {printf(我是进程%d\n,getpid());pid_t id fork();if(id 0){printf(我是子进程%d\n,getpid());}else{printf(我是父进程%d\n,getpid());} } 运行的结果就是 可以看见子进程从fork返回后开始执行不会重复fork之前的代码。这是因为内核复制了父进程的执行上下文包括EIP/RIP寄存器让子进程直接从fork的下一条指令继续运行。父子进程的执行顺序由内核调度器决定不同系统可能有不同表现。 1.2 fork函数返回值 fork函数的返回值主要有三种当fork运行错误时会返回-1。当运行成功时对于子进程会返回0对于父进程会返回子进程的pid 1.3 写时拷贝 通常父子进程的代码是共享的。当父子进程都不再写入数据时他们的数据也是共享的。当任意一方试图写入数据就会触发写时拷贝使其各自的数据分开来。 我在上文讲到过isexist借此也给大家介绍了写时拷贝的机制它本质上是依靠页表来实现的。 在fork之后父进程首先要做的事将代码与数据的权限全部改为只读所以子进程的权限也是只读。子进程尝试修改页表会识别对只读区域进行写入触发系统错误导致 缺页中断让系统去做检测如果修改的是代码区那就直接杀进程如果是数据区因为数据区本身就是读写权限可现在是只读那就判定为发生写时拷贝。 为什么要在申请新的内存空间的基础上将原本的数据拷贝一份呢因为新的数据的修改可能是在原本数据上的覆盖比如count。 写时拷贝,是⼀种延时申请技术,可以提高整机内存的使用率。因为有写时拷贝技术的存在,所以父子进程得以彻底分离完成了进程独立性的技术保证! 1.4 fork的常规用法 说到底fiork有两种常规的用法   1、一个父进程希望创建子进程复制自己随后使得父子进程执行不同的代码段。例如父进程等待客户端请求生成子进程来处理请求。 #includestdio.h #includeunistd.h #includesys/types.hint main() {pid_t id fork();if(id 0){printf(我是子进程%d,我的父进程是%d\n,getpid(),getppid());printf(执行子进程专属代码);sleep(3);}else if(id 0){printf(我是父进程%d,我的子进程是%d\n,getpid(),id);printf(执行父进程专属代码);sleep(1);}else{printf(fork失败\n);}return 0; } 2、一个进程要执行一个不同的程序。例如子进程从fork返回后调用exec等一系列的函数。 #includestdio.h #includeunistd.h #includesys/types.h #include sys/wait.h #includecstdlibint main() {pid_t pid fork();if (pid 0) {// 子进程加载新程序execl(/bin/ls, ls, -l, NULL);// 若exec失败才会执行以下代码perror(exec failed);_exit(EXIT_FAILURE); // 必须用_exit避免刷新父进程缓冲区} else if (pid 0) {// 父进程继续执行原程序waitpid(pid, NULL, 0); printf(子进程已退出\n);}return 0; } 大家可能对exec系列的函数不太熟悉包括我们所使用的配套的waitpid没关系我们会在后面的内容进行讲解这里只是给大家示范一下第二种用法。 二、进程终止  进程终止是操作系统管理进程生命周期的关键环节其本质是释放系统资源就是释放进程申请的相关内核数据结构和对应的数据与代码。 2.1、退出码 在C标准库中存在着errno与strerror这对组合。error是一个定义在errno.h的全局变量strerror通过传进来的出错误码errno可以给出字符串。通过打印这个字符串就能够让我们知道错误的原因。 errno 负责捕获错误本质strerror 负责翻译错误真相二者协作构成了 Linux 系统编程中高效、精准、标准化的错误处理基石。 例如在文件操作中我们有时经常出现错误 int main() {//打开文件前的错误信息printf(errno: %d ,errstring: %s\n,errno,strerror(errno));FILE*fpfopen(./log.txt,r);if(fpnullptr){//打开文件失败后的错误信息printf(errno: %d ,errstring: %s\n,errno,strerror(errno));return errno;}return 0; } 在我系统下没有./log.txt时就会出错此时我们就能获取原因No such file or directory不存在这样一个文件或者目录 那么系统中给我们提供了多少个错误码呢 根据操作系统的不同有着不同的错误码我们看一眼试着打印一下linux系统的 int main() {for(int i1;i200;i){std::couti: strerror(i)std::endl;}return 0; } 结果如下 1: Operation not permitted 2: No such file or directory 3: No such process 4: Interrupted system call 5: Input/output error 6: No such device or address 7: Argument list too long 8: Exec format error 9: Bad file descriptor 10: No child processes 11: Resource temporarily unavailable 12: Cannot allocate memory 13: Permission denied 14: Bad address 15: Block device required 16: Device or resource busy 17: File exists 18: Invalid cross-device link 19: No such device 20: Not a directory 21: Is a directory 22: Invalid argument 23: Too many open files in system 24: Too many open files 25: Inappropriate ioctl for device 26: Text file busy 27: File too large 28: No space left on device 29: Illegal seek 30: Read-only file system 31: Too many links 32: Broken pipe 33: Numerical argument out of domain 34: Numerical result out of range 35: Resource deadlock avoided 36: File name too long 37: No locks available 38: Function not implemented 39: Directory not empty 40: Too many levels of symbolic links 41: Unknown error 41 42: No message of desired type 43: Identifier removed 44: Channel number out of range 45: Level 2 not synchronized 46: Level 3 halted 47: Level 3 reset 48: Link number out of range 49: Protocol driver not attached 50: No CSI structure available 51: Level 2 halted 52: Invalid exchange 53: Invalid request descriptor 54: Exchange full 55: No anode 56: Invalid request code 57: Invalid slot 58: Unknown error 58 59: Bad font file format 60: Device not a stream 61: No data available 62: Timer expired 63: Out of streams resources 64: Machine is not on the network 65: Package not installed 66: Object is remote 67: Link has been severed 68: Advertise error 69: Srmount error 70: Communication error on send 71: Protocol error 72: Multihop attempted 73: RFS specific error 74: Bad message 75: Value too large for defined data type 76: Name not unique on network 77: File descriptor in bad state 78: Remote address changed 79: Can not access a needed shared library 80: Accessing a corrupted shared library 81: .lib section in a.out corrupted 82: Attempting to link in too many shared libraries 83: Cannot exec a shared library directly 84: Invalid or incomplete multibyte or wide character 85: Interrupted system call should be restarted 86: Streams pipe error 87: Too many users 88: Socket operation on non-socket 89: Destination address required 90: Message too long 91: Protocol wrong type for socket 92: Protocol not available 93: Protocol not supported 94: Socket type not supported 95: Operation not supported 96: Protocol family not supported 97: Address family not supported by protocol 98: Address already in use 99: Cannot assign requested address 100: Network is down 101: Network is unreachable 102: Network dropped connection on reset 103: Software caused connection abort 104: Connection reset by peer 105: No buffer space available 106: Transport endpoint is already connected 107: Transport endpoint is not connected 108: Cannot send after transport endpoint shutdown 109: Too many references: cannot splice 110: Connection timed out 111: Connection refused 112: Host is down 113: No route to host 114: Operation already in progress 115: Operation now in progress 116: Stale file handle 117: Structure needs cleaning 118: Not a XENIX named type file 119: No XENIX semaphores available 120: Is a named type file 121: Remote I/O error 122: Disk quota exceeded 123: No medium found 124: Wrong medium type 125: Operation canceled 126: Required key not available 127: Key has expired 128: Key has been revoked 129: Key was rejected by service 130: Owner died 131: State not recoverable 132: Operation not possible due to RF-kill 133: Memory page has hardware error 134: Unknown error 134 135: Unknown error 135 ...省略 195: Unknown error 195 196: Unknown error 196 197: Unknown error 197 198: Unknown error 198 199: Unknown error 199 可以看得出来有133个是系统规定了的错误类型。  同学们那我们就必须要使用系统给的错误码吗 不是的我们写的代码跟系统强相关自然可以使用系统给的错误码。写的毫无关系自然可以自己规定一套错误码。 2.2、进程终止的方式 一般来说程序正常终止有三种情况我们在linux系统下可以通过echo $?指令来查看进程的退出码 1、从main函数返回 2、任意地方调用exit 3、_exit终止 异常退出 ctrl c退出信号终止 在退出的时候程序可以给我们返回退出码随后让我们的值他是否完成了预期的任务。其基本思想就是我们规定程序返回代码0时才表示执行成功返回其他任意代码都被视为不成功。 大家在学习C语言或者C语言时曾经天天都在写main函数。main函数也是一个函数自然有自己的返回值。main函数的返回值类型主要有两种类型最主要的是int main另外一个是void mainvoid就是没有返回值。那么大家有没有想过为什么main函数会有返回值呢这个返回值又能给谁呢 答案是返回给父进程或者系统。 我们通过子进程的main函数的返回值就能确定子进程的执行的结果。这其实也是我们前面提到过一点的。return n等同于执⾏exit(n),因为调⽤main的运⾏时函数会将main的返回值当做 exit的参数。 main函数中的exit0可以平替return 0但是在其他地方不能平替。 比如非main函数的return其实只代表这个函数的结束但是非main函数调用exit代表进程的结束。 而exit与_exit呢他们的主要区别还是在于exit最后也会调用_exit, 但在调用_exit之前还做了其他⼯作 1、执⾏⽤⼾通过 atexit或on_exit定义的清理函数。 2、关闭所有打开的流所有的缓存数据均被写入 3、 调⽤_exit 我们给大家做个演示 int main() {printf(你好这是一个打印);exit(0); } 这个程序的运行结果是 而我们使用_exit() int main() {printf(你好这是一个打印);_exit(0); } 什么也都不会打印,这是因为exit() 属于标准 C 库函数它会 1、刷新所有 stdio 缓冲区包括 printf 未刷新的输出 2、 调用通过  atexit()  注册的清理函数 3、 最终调用  _exit()  系统调用终止进程 而_exit() 是直接的系统调用定义在 unistd.h它会 1、立即终止进程不刷新任何缓冲区 2、跳过所有标准库的清理流程 3、由于 printf 的输出在行缓冲模式下无换行符 \n未被刷新内容丢失 三、进程等待 一般而言父进程创建了子进程父进程就要等待子进程直到子进程结束。  3.1、等待的必要性 为什么需要父进程来等待呢 之前在进程状态时讲过子进程退出如果父进程不管不顾就可能造成僵尸进程的问题进而造成内存泄漏。 另外进程一旦变成僵尸状态那就刀枪不入哪怕使用kill函数调用也无能为力因为谁也没有办法杀死一个已经死去的进程。 最后父进程派给子进程的任务完成的怎么样了我们需要知道如子进程运行完成结果是对是错或者是否正常退出。 总的来说父进程通过进程等待的方式回收子进程资源获取子进程退出的相关信息。 3.2 wait与waitpid 我们主要有两个函数来进行父进程的等待wait与waitpid   pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int options); status是一个指向整数类型的指针用于存储子进程的退出信息如果为空指针就表示不关心子进程的退出状态他是一个输出型的参数我们可以用这个参数来检查子进程的退出状态。 函数运行成功后会返回终止的子进程的PID如果失败了就返回-1并且设置errno。 使用wait函数时当我们的子进程一直不退出父进程就会阻塞到wait函数内部。  对于waitpid的参数pid指定要等待的子进程 pid大于0时等待进程ID等于pid的子进程pid为-1时代表任意一个子进程类似于wait等于0时等待与调用进程同进程组的任意子进程小于0时等待进程组ID等于pid绝对值的任意子进程。 status参数同上是一个输出型参数。options参数用于控制函数行为可组合使用 WNOHANG非阻塞模式如果没有子进程退出立即返回0 WUNTRACED也返回停止的子进程状态 WCONTINUED也返回已继续的子进程状态 我们写点代码来认识一下这几个函数 wait int main() {pid_t id fork();if(id 0){int cnt10;while(cnt--){printf(子进程运行中%d\n,getpid());sleep(1);} }else if(id 0){pid_t ridwait(nullptr);if(rid0){printf(等待成功rid%d\n,rid);}while(1){printf(我是父进程%d\n,getpid());sleep(1);}}else{printf(errno: %d ,errstring: %s\n,errno,strerror(errno));return errno;}return 0; } 这个代码创建了一个子进程运行十秒钟之后让父进程用wait来回收子进程  运行以上代码在另外一个bash中输入以下指令进行循环的进程状态查看 while :; do ps ajx | head -1 ps ajx | grep test; sleep 1; done 我们可以看到这个结果 可以看见过程中并未出现僵尸状态因为僵尸已经被我们父进程回收了。 那我们在使用一下waitpid吧我先将以上的代码简单的更改一下 waitpid int main() {pid_t id fork();if(id 0){int cnt3;while(cnt--){printf(子进程运行中%d\n,getpid());sleep(1);} exit(123);//我们设定一下子进程的退出码为123}else if(id 0){//pid_t ridwait(nullptr);int status;pid_t ridwaitpid(id,status,0);if(rid0){printf(Child %d exited with status %d\n,rid, status);//试着让父进程打印一下status}while(1){printf(我是父进程%d\n,getpid());sleep(1);}}else{printf(errno: %d ,errstring: %s\n,errno,strerror(errno));return errno;}return 0; } 我们故意让子进程退出码信息为123然后再父进程回收时打印status却发现打印的status的结果不是123 这是怎么回事呢 status的提取问题  status不能简单的当作整形来看待可以当作位图来看待具体细节如下图只研究status低16 比特位 也就是说我们想要查看进程的退出码我们需要提取出低16位的高八位status 8 0xFF,我们也有一个标准宏来实现这个过程WEXITSTATUSstatus。 阻塞options的问题我们之后在谈 四、重谈进程退出 了解了以上的知识我们就知道了一般来说进程退出有三种情况 1、代码跑完了结果是对的返回0。 2、代码跑完了结果不对返回非0。 3、代码没跑完异常了。 前两种是我们一直在说的通过退出码判定最后一种这是最复杂的情况通常是被信号(Signal)终止的 进程退出信息会记录退出的退出信号低7位。也就是说status会同时记录退出码与退出信号同样可以通过标准宏的手段让我们知道退出信号是什么。 常见的退出信号原因包括但不限于 除零错误 (SIGFPE) 段错误 (SIGSEGV) 用户中断 (SIGINT, 如CtrlC) 强制终止 (SIGKILL) 总线错误 (SIGBUS) 以野指针来说我们之前提到过 野指针实际上指向的是虚拟地址在使用的时候可能会出现指向的那个地址权限不对或者根本不存在对应映射所以可能会杀掉进程 导致程序崩溃。 杀掉进程的手段就会触发段错误(Segmentation Fault)系统发送SIGSEGV信号信号编号11给进程。 总结 我们本篇文章主要是讲了进程创建进程的终止以及进程等待的部分内容了解了写时拷贝以及退出码等信息。关于进程的等待还有一点内容options参数并未向大家详细介绍这个我会放在下一篇文章讲解。 关于进程的控制这一章节我打算划分两篇给大家讲解下一篇的内容应该包含进程等待的阻塞选项问题然后会为大家讲一下进程的替换的内容这一部分非常重要并借此给大家简单展示一下每隔xx秒就自动存档记录的原理。讲完进程替换就会为大家基于我们之前所学的所有内容做一个进程的总结并以此写一个我们shell的模拟实现就是我们平时使用的SHell命令行解释器的模拟实现。 鼠鼠我最近要备战期末周所以更新肯定会延迟到月底去了希望大家多多包含祝福我高数下别挂科我高数上都没学过就直接让我学高数下吗有意思。 月底再跟大家见面啦希望本篇文章的内容能够对您有所帮助谢谢
http://www.w-s-a.com/news/40919/

相关文章:

  • 塔式服务器主机建网站定制美瞳网站建设
  • 网站是先解析后备案吗永久免费网站模板
  • wordpress站点演示php根据ip 跳转网站
  • 东莞市凤岗建设局网站网站开发有哪些职位
  • 企业网站手机版模板免费下载辣条网站建设书
  • 南昌网站建设维护vc 做网站源码
  • 网站动态logo怎么做织梦移动端网站怎么做
  • 三亚城乡建设局网站app下载安装官方网站
  • 公司被其它人拿来做网站郑州哪家做网站最好
  • 山东省建设厅官方网站抖音代运营业务介绍
  • 网站制作 牛商网wordpress商城 微信支付
  • 平面设计培训网站建文帝网站建设
  • python网站建设佛山乐从网站建设
  • 网站 免费 托管运营app软件大全
  • 爱网站找不到了网站设计制作要交印花税
  • 分销平台是什么意思网站如何从行为数据进行优化
  • 做网站公司职务做民俗酒店到哪些网站推荐
  • 从0到建网站wordpress导航主题模板下载地址
  • 以3d全景做的网站统计网站的代码
  • 北辰网站建设WordPress换主题文件夹
  • 做网站的合同范文百度分析工具
  • 深圳企业网站制作公司单位注册wordpress发送邮件
  • 兰州专业网站建设团队wordpress 拉取点击数
  • 基于php房产网站开发ppt模板免费下载第一ppt
  • 网站盈利模式分析怎么做山东营销网站建设联系方式
  • 二级网站建设 知乎我的个人主页模板
  • wordpress小说网站模板下载地址百度优化服务
  • 云南网页设计制作seo计费系统源码
  • 屏蔽ip网站吗行业外贸网站建设
  • 河北城乡建设学校网站常州网站建设公司平台