网站注册公司,南京做网站的公司有哪些,贵阳专业做网站的公司有哪些,朝阳 手机网站 建设经典五问#xff1a;
1.什么是程序#xff1f;什么是进程#xff1f;
从是否运行进行判断: gcc xxx -o pro#xff0c;磁盘中生成的pro文件#xff0c;就是程序 进程是程序一次运行活动
程序是静态的概念#xff0c;进程是动态的概念。 2.如何查看系统中的进程:
在l…经典五问
1.什么是程序什么是进程
从是否运行进行判断: gcc xxx -o pro磁盘中生成的pro文件就是程序 进程是程序一次运行活动
程序是静态的概念进程是动态的概念。 2.如何查看系统中的进程:
在linux中
a.使用ps(-aux) 命令查看使用 grep命令过滤 例如: ps -aux | grep init
b. top 指令类似window的任务管理器 3.什么是进程标识符: 每一个进程 都有一个非负整数 表示唯一ID叫 pid pid0称为交换进程(swapper)作用--进程调度 pid1,init进程作用 -- 系统初始化
调用getpid() 函数获取自身的进程id
getppid() -- 获取父进程id #include sys/types.h #include unistd.h int main() { pid_t pid; pid getpid(); printf(pid %d\n,pid); while(1); return 0; } 4. 什么叫父进程什么叫子进程 if 进程A创建了进程B那么A是B 的父进程B是A的子进程。 5.C程序存储空间是如何分配 高地址 ------------------------ 低地址
命令行参数和环境变量----- 栈(函数里的形参 和 局部变量) ------- 堆(malloc等动态内存函数申请的内存空间) ------------未初始化的数据(BSS段 int a;) --------初始化的数据数据段 int b10;-----正文(代码段) int a 0; //全局初始化区 char *p1; //全局未初始化区 void main() { int b; //栈 char s[] “abc“;//栈 char *p2; //栈 char *p3 “123456“; //123456\0在常量区p3在栈上体会与 char s[]abc; 的不同 static int c 0 //全局初始化区 p2 (char *)malloc(20); //堆区 strcpy(p1, “123456“); //123456\0在常量区编译器可能将它与p3指向的 “123456 “优化成一块 } 参考自什么变量存放在栈和堆_什么样的数据进堆 什么样的数据进栈-CSDN博客 fork函数 进程函数 fork 使用:
头文件: #include sys/types.h #include unistd.h函数原型: pid_t fork(void); 返回值: 调用成功调用一次返回两次 0--代表当前进程是子进程 非负数 -- 代表是父进程
调用失败放回-1
--------------------------------------
fork_case: case1 : 证明fork() 之后的语句父子进程都会执行fork之前的语句只有父进程执行 #include sys/types.h #include unistd.h int main() { pid_t pid1; pid_t pid2; pid1 getpid(); printf(Before fork,pid%d\n,pid1); fork(); //创建一个进程 pid2 getpid(); printf(After fork,pid%d\n,pid2); if(pid1 getpid()){ printf(This is father print. fatherPid%d\n,pid1); } else { printf(This is child print. childPid%d\n,pid2); } return 0; } -------------------------------- case2:验证: fork 返回值fork调用一次返回两次0 父进程 0子进程 #include sys/types.h #include unistd.h int main() { pid_t pid; pidgetpid(); printf(father pid %d\n,pid); pidfork(); if(pid0){//父进程 printf(This is father print,pid%d\n,getpid()); } else if(pid 0){ //子进程 printf(This is child print,pid%d\n,getpid()); } return 0; } ---------------------------- case3: 探索fork 父进程返回大于0的数有什么意义
等于子进程Pid号子进程返回值就是0 //why给返回0的理由:pid0被交换进程所占用不可能作为他的pid #include sys/types.h #include unistd.h int main() { pid_t pid; pid_t pid2; pid_t retpid; pidgetpid(); printf(father pid %d\n,pid); retpidfork(); pid2getpid(); if(pidpid2){//父进程 printf(This is father print,retpid%d, pid%d\n,retpid,pid2); } else { //子进程 printf(This is child print,retpid%d, pid%d\n,retpid,pid2); } return 0; } fork创建进程发生了什么 进程早期设计的时候把全拷贝--内存-空间所有内容都进行了拷贝 后面写时拷贝(不变的内容放在共享空间不拷贝)只对copy on write- COW- 子进程 修改的内存进行单独拷贝
执行 fork 以后: fork之后的代码会被直接拷贝下来给父子进程调度使用 父子进程的变量独立子进程改变自己的变量父进程不受影响(因为子进程实际拷贝了一份单独的内存空间和父进程独立) case:父子进程内存空间独立 #include sys/types.h #include unistd.h int main() { pid_t pid; pid_t pid2; int a88; pidgetpid(); printf(father pid %d\n,pid); fork(); pid2getpid(); if(pidpid2){//父进程 printf(This is father print, pid%d\n,pid2); } else { //子进程 printf(This is child print, pid%d\n,pid2); a12; } printf(a%d\n,a); return 0; } fork 创建子进程的目的: 1)父进程希望复制自己使父子进程同时执行不同的代码段。 -- 常见于网络服务 2)一个进程要执行一个不同的程序。这在shell中常见这种情况下子进程从fork返回后立即调用exec() case:模拟网络服务(1 #include sys/types.h #include unistd.h #include stdio.h int main() { pid_t pid; pid_t pid2; int data 0; while (1) { printf(please input a data\n); scanf(%d, data); if (data 1) { pid fork(); // 每次近来创建一个子进程 if (pid 0) { // 父进程 } else { // 子进程 while (1) { printf(net request,pid%d\n, getpid()); sleep(10); } } } else { puts(waitting,do noting); } } return 0; } vfork()函数 vfork 和fork的区别: 1.vfork是直接使用父进程的存储空间不拷贝 2.vfork保证子进程先运行当子进程调用exit()后父进程才执行
case 区别验证 #include sys/types.h #include unistd.h #includestdio.h #includestdlib.h int main() { pid_t pid; int cnt0; pid vfork(); if (pid 0) { while (1) { printf(cnt %d\n,cnt); printf(this is father pid%d\n, getpid()); sleep(1); } } else { while (1) { printf(this is child pid%d\n, getpid()); sleep(1); cnt; if(cnt5){ exit(0); } } } return 0; } 进程退出:
正常退出: 1.Main 函数return 2.进行调用exit标准C库 3.进程调用_exit() 或者_Exit(),属于系统调用 补充:一个进程包含多个线程当最后一个线程结束的时候进程就退出了 1.进程最后一个线程放回 2.最后一个线程调用 pthread_exit 异常退出: 1.调用 abort 2.当进程接收到接收信号如 ctrlc 3.最后一个线程对取消(cancellation)请求做出响应 //无论进程如何退出最后都会执行内核的同一段代码这段代码为所有相关进程关闭所有打开描述符释放他的所有存储器
子进程调用exit _exit _Exit 的时候父进程可以调用waitpid 查看子进程退出的状态
推荐 exit() 是对_exit() _Exit()的封装先处理缓冲区再退出 等待子进程退出:wait() 收集退出状态
why? 创建子进程目的: 子进程退出状态if不被收集会变成僵尸进程 通过ps可以发现他的状态Z --僵尸进程父进程--S运行中 #include sys/types.h #include sys/wait.h pid_t wait(int *wstatus); pid_t waitpid(pid_t pid, int *wstatus, int options); int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); status参数: 是一个整形数值指针 非空 子进程退出状态 放在他所指向的地址中 空: 不关心退出状态 检测wait和waitpid所放回终止状态的宏: WEXITSTATUS(status); -- 正常退出 WIFSIGNALED(status) --异常退出 WIFSTOPPED(status) -- 暂停子进程的返回状态 WIFCONTINUED(status) -- 暂停好继续 的子进程放回的状态 wait下的父进程 - 如果所有子进程都还在进行则阻塞 -一个子进程已经终止正等待父进程获取其终止状态则该子进程终止状态立刻返回 -如果父进程没有终止子进程则出错返回
wait 和 waitpid 区别: wait使调用者阻塞waitpid有一个选项可以使得调用者不阻塞 当option WBOHANG 的时候 不阻塞 孤儿进程:
概念 父进程先于子进程退出使得子进程变成孤儿进程 linux系统为了避免出现过多的孤儿进程init进程来收留孤儿进程init进程就是孤儿进程的父进程
验证程序 #include sys/types.h #include unistd.h #includestdio.h #include sys/types.h #include sys/wait.h #includestdlib.h int main() { pid_t pid; int cnt0; int status10; pid fork(); if (pid 0) { printf(this is father pid%d\n, getpid()); } else if(pid0) { while (1) { printf(this is child pid%d\t my father ppid%d\n, getpid(),getppid()); sleep(1); cnt; if(cnt3){ exit(3); } } } return 0; } exec族函数 但一个进程跑到一半的时候调用exec族函数去执行另一个程序.
exec函数族: execl,execlp, execv,execvp ,execle ,execvpee结尾不常用
返回值: exec成功不会放回失败设置error并返回 -1然后从原程序调用点往下执行
参数说明: path可执行文件路径 arg可执行程序所带参数第一个参数是程序名没有带路径且arg必须以NULL结束 file: 如果参数中包含/则视为路径否则就按PATH环境变量在他所在目录中搜寻可执行文件 perror -- 打印出错误信息 perror(why); why: 错误信息
execl例子: #includestdio.h #includeunistd.h #includestdlib.h int main() { printf(before execl\n); if(execl(./echo,echo,abc,NULL)-1){ puts(execl error!!!); perror(why); } puts(after execl); return 0; } #includestdio.h int main(int argc,char **argv) { int i; for(i0;iargc;i){ printf(argv[%d]%s\n,i,argv[i]); } return 0; } gcc echoarg.c -o echo -------------------------------------------
execl(/bin/ls,ls,-l,NULL) -- 第一个参数直接写绝对路径调用系统的命令
execl(/bin/date,date,NULL)-1) -- 获取系统时间 execlp -- p 通过系统环境变量找到指令不用写绝对路径了 such as: execlp(ps,ps,NULL,NULL)-1) v -- 使用指针char * [](字符串数组-二维数组)代替参数 #includestdio.h #includeunistd.h #includestdlib.h int main() { printf(before execl\n); char *argv[]{ps,NULL,NULL}; if(execvp(ps,argv)-1){ puts(execl error!!!); } puts(after execl); return 0; } exec 配合 fork使用:
case1 实现功能当父进程检测到输入为1 的时候创建子进程吧配置文件的字段修改掉 #include stdio.h #include sys/types.h #include fcntl.h #include unistd.h #include stdlib.h #include string.h int main() { pid_t pid; pid_t pid2; int data 0; while (1) { printf(please input a data\n); scanf(%d, data); if (data 1) { pid fork(); // 每次近来创建一个子进程 if (pid 0) { // 子进程 int fdSrc; char *readBuf NULL; fdSrc open(./config.txt, O_RDWR); int size lseek(fdSrc, 0, SEEK_END); lseek(fdSrc, 0, SEEK_SET); readBuf (char *)malloc(sizeof(char) * (size 8)); int n_read read(fdSrc, readBuf, size); char *p strstr(readBuf, LENG); if (p NULL) { puts(not found); exit(-1); } p p strlen(LENG); *p 5; lseek(fdSrc,0,SEEK_SET); write(fdSrc,readBuf,strlen(readBuf)); close(fdSrc); } } else { puts(waitting,do noting); } } return 0; } ---------------------- execl进行优化: #include stdio.h #include sys/types.h #include fcntl.h #include unistd.h #include stdlib.h #include string.h #include sys/wait.h int main() { pid_t pid; pid_t pid2; int data 0; while (1) { printf(please input a data\n); scanf(%d, data); if (data 1) { pid fork(); // 每次近来创建一个子进程 if(pid0){ wait(NULL);//防止变成】僵尸进程 } else if (pid 0) { // 子进程 execl(./changedata,changedata,NULL); } } else { puts(waitting,do noting); } } return 0; } system进行优化: #include stdlib.h int system(const char *command); system -- 封装后的exec
调用/bin/sh失败返回127 其他失败返回-1
与exec 的区别执行完后还会回去执行原程序的代码 一句system调用就可以执行之前的整个可执行文件 #include stdio.h #include sys/types.h #include fcntl.h #include unistd.h #include stdlib.h #include string.h #include sys/wait.h int main() { system(./exf);// 前面生成的可执行文件直接调用即可 return 0; } popen #include stdio.h FILE *popen(const char *command, const char *type); int pclose(FILE *stream); 可以获取内存的输出结果: #include stdio.h #include sys/types.h #include fcntl.h #include unistd.h #include stdlib.h #include string.h #include sys/wait.h int main() { char ret[1024]{0}; FILE *fp; fppopen(ps,r); //size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); int nread fread(ret,1,1024,fp); printf(nread%d\nret %s\n,nread,ret); return 0; }