Linux—进程控制
来源:互联网 发布:初中毕业可以学编程吗 编辑:程序博客网 时间:2024/06/06 04:01
1、system 函数 :在一个进程中执行另一个程序
//原型:#include<stdio.h>int system(const char* command);//,这里将要执行的命令作为参数传递给system函数,不需要自己来调用fork,exec,和waitpid,也不需要自己来处理错误,处理信号,(但是调用system效率低)调用成功,返回相应命令的退出状态码,如果无法启动shall则返回127,发生其他错误时返回-1;
system函数使用如下:
#include<stdio.h>#include<stdlib.h>int main(){ printf("Running ps whit system\n"); system("ps -ef");// 调用psm命令查看系统进程 printf("Done.\n"); return 0;}
通过验证得到:bash创建了system进程,system进程会创建出一个shell进程来执行最终的命令
2、exec家族(进程程序的替换)
用fork创建子进程后执行的是与父进程相同的程序(可能会执行不同的代码分支),子进程往往需要调用一种exec函数来执行另一个程序,当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的main函数 开始执行,调用exec函数并不创建新进程,所以调用exec前后该进程的id并没有发生改变
#include<unistd.h>extern char** environ;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函数只有出错的返回值,没有成功的返回值
函数基本用法:
实例程序:
#include<unistd.h>#include<stdlib.h>#include<stdio.h>int main(){ printf("Running ps with execlp\n"); execlp("ps","ps","ax","NULL"); //execl("/bin/ls","ls","-a","-l","-n",NULL);//char* _argv[]={"ls","-a","-l","-n",NULL};//execvp("ls",_argv); printf("Done\n"); return 0;}//也可以用于子进程中
3、进程创建
#include<unistd.h> pid_t fork(void); //函数调用一次,成功时返回两次,子进程的返回值为0,父进程的返回值为子进程的pid,失败返回-1,并设置全局变量error#include <unistd.h>#include<sys/types.h>pid_t vfork(void);//与fork调用和返回值相同,不同在于vfork创建的子进程会堵塞父进程,它也并不是将父进程的地址空间完全复制到子进程中,vfork保证了子进程先运行,在子进程执行了exec函数之后应该调用_exit返回(不能调用return),父进程才会被调用 //在子进程中,如果使用return 返回,就意味着main函数结束了,因为栈是父进程共享的,所以程序的函数栈发生了变化,main函数return之后,通常会调用exit系函数,父进程收到子进程的exit之后,就会开始从vfork返回,但是这时候整个main函数的函数栈都已经不复存在了,所以父进程压根无法返回,
4、wait 与 waitpid 函数
#include<sys/types.h>#include<sys/wait.h>pid_t wait(int* status );//等待任意子进程的结束,status:输出参数,用于获取子进程的退出状态,如果调用者不关心,可设置为null;pid_t waitpid(pid_t pid,int* status,int options);//等待指定子进程的结束 pid :要等待的子进程的ID,值为-1时,称为等待任意进程,options:意为不阻塞调用者进程,常见选项为WNOHANG成功时返回子进程的pid,出错时返回-1,对于waitpid(),若指定了WNOHANG选项,但没有子进程终止,则返回0;
调用wait与waitpid可能会发生的情况:
(1)、阻塞,如果其所有子进程都还在运行
(2)、如果一个子进程已经终止,正等待的父进程获取其终止状态,取得之后立即返回
(3)、出错立即返回(如果没有任何子进程)
#include<stdio.h> //进程的非阻塞式等待#include<unistd.h>#include<stdlib.h>#include<sys/wait.h>int main(){ pid_t pid; pid = fork(); if (pid < 0) { printf("%s fork error\n", _FUNCTION_); return 1; } else if (pid == 0)//child { printf("chlid is run, pid is:%d\n", getpid()); sleep(5); exit(1); } else { int status = 0; pid_t ret = 0; do { ret = waitpid(-1, &status, WNOHANG);//非阻塞式等待 if(ret == 0) { printf("child is running\n"); } sleep(1); }while(ret == 0); if (WIFEXITED(status) && ret == pid) { printf("wait child 5s success,child return code is:%d\n", WEXITSTATUS(status)); } else { printf("wait child failed,return.\n"); return 1; } } return 0;}
#include<stdio.h> //进程阻塞式等待#include<unistd.h>#include<stdlib.h>#include<sys/wait.h>int main(){ pid_t pid; pid = fork(); if (pid < 0) { printf("%s fork error\n", _FUNCTION_); return 1; } else if (pid == 0)//child { printf("chlid is run, pid is:%d\n", getpid()); sleep(5); exit(257); } else { int status = 0; pid_t ret = waitpid(-1, &status, 0);//阻塞式等待,等待5秒 printf("this is test for wait\n"); if (WIFEXITED(status) && ret == pid) { printf("wait child 5s success,child return code is:%d\n", WEXITSTATUS(status)); } else { printf("wait child failed,return.\n"); return 1; } } return 0;}
模拟实现shall 功能
#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<sys/wait.h>#include<sys/types.h>int main(){ while (1) { printf("[myshall@name mn]# "); fflush(stdout);//刷新缓冲区 char buf[1024]; size_t ret = read(0, buf, sizeof (buf)-1);//从标准输入键盘中获取字符串存放在buf中 if (ret > 0) { buf[ret - 1] = 0;//将最后一个‘\n’赋值为0; } char* _argv[32];//指针数组 char* start = buf;//start的指针指向获取的命令 _argv[0] = start; int i = 1; while (*start) { //字符串分解为命令存放在——argv[]中 if (*start == ' ') { *start = '\0';//一个命令结束 start++; _argv[i++] = start; } else { start++; } } _argv[i] = NULL; pid_t id = fork();//创建子进程并调用execvp()函数 if (id == 0) { //重定向>的实现 int j=0; for(j=0;j<=i;++j) { if(_argv[j] =='>' ) //寻找重定向‘>’ { char* file=_argv[j+1]; //重定向的文件名 _argv[j]=NULL; //改变指针数组的有效大小 ,只执行j以前 close(1); //关闭标准输出显示器 文件描述符1 while(1) { if(open(file,O_WRONLY|O_CREAT|O_TRUNC,0666) ==1) //打开重定向的文件,成功返回的文件描述符则为1 break; else { printf("open fail"); } } //程序替换 execvp(_argv[0],_argv); exit(1); } else //father //父进程只等待子进程结束 { pid_t ret=waitpid(id,NULL,0); } } } return 0;}
阅读全文
0 0
- Linux—进程控制
- Linux 进程控制——进程调度
- linux进程及进程控制
- linux进程及进程控制
- linux进程及进程控制
- linux进程及进程控制
- Linux 进程控制—— exec“金蝉脱壳”
- Linux 进程控制—— exec“金蝉脱壳”
- Linux——进程的控制 信号
- Linux内核开发 — 进程控制
- 【Linux】进程控制—exec函数族
- LINUX进程控制
- Linux 进程控制
- linux进程控制
- linux进程控制
- Linux的进程控制
- linux进程控制
- LINUX进程控制 笔记
- comparator接口与Comparable接口的区别
- Java(android)通过请求头(User-Agent)获取浏览器类型,操作系统类型,手机机型
- 查询,生成结果表
- Java基础
- js加var和不加var的区别
- Linux—进程控制
- 【PMP认证考试之个人总结】第 11 章 项目采购管理
- Android Studio 打包时 Signature Version V1 V2
- Palindrome_Number
- lua的缓动函数列表
- struts2值栈与action上下文
- [Qt]QCombobox下拉列表文字显示一半的问题
- Vue基础之组件
- Java基础