1进程控制
1.1fork{int fork(void)}
1.1.1 返回值
返回值 | 含义 |
---|---|
-1 | 失败 |
0 | 子进程逻辑控制流 |
其他(子进程PID) | 父进程逻辑控制流 |
1.1.2特点
1: 调用一次,返回两次
2:相同但是独立的地址空间
3: 并发执行
int main(int argc,char *argv[]){
int n=atoi(argv[1]);
int i;
for(i=0;i<n;i++){
int pid=fork();
if(pid==0){
printf("%d PID:%d\n",i,getpid());
exit(0);
}else{
printf("%d create %d\n",i,pid);
}
}
}
4: 共享文件
#include <stdio.h>
#include <unistd.h>
int i = 100;
int main(){
int j=100;
FILE* fd = fopen("./test","w+");
pid_t pid = fork();
if(pid == 0){// child
int k;
for(k=0;k<10000;k++)
fprintf(fd,"this is childi%d\t j%d\n",++i,++j);
}else{
int k;
for(k=0;k<10000;k++)
fprintf(fd,"this is fatheri%d\t j%d\n",--i,--j);
}
}
1.1.3问题
1:子进程创建成功后 代码的执行位置?
父进程执行到那,子进程就从那开始执行
2:父子进程执行的顺序?
并发执行 谁抢到cpu谁执行
1.2getpid getppid
函数 | 接口 |
---|---|
pid_t getpid() | 获取当前进程ID |
pid_t getppid() | 获取当前进程父进程ID |
查看进程的PID和PPID
ps -o pid,ppid,cmd,s
1.3创建多进程
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<mqueue.h>
#include<sys/mman.h>
#include<string.h>
#include<pthread.h>
#include<sys/syscall.h>
#include<sys/prctl.h>
#include<signal.h>
#include<sys/wait.h>
#include<sys/types.h>
void handle(int sig){
printf("%d exit\n",wait(3));
}
int main(int argc,char *argv[]){
signal(SIGCHLD,handle);
int n=atoi(argv[1]);
int i;
for(i=0;i<n;i++){
int pid=fork();
if(pid==0){
printf("%d PID:%d\n",i,getpid());
break;//防止有孙子进程 只要是子进程都跳出
}else{
printf("%d create %d\n",i,pid);
}
}
}
#2
2进程之间数据共享
2.1特点
2.2全局变量
父子进程之间不能使用全局变量通信 因为两个进程间内存不能共享
3exec函数族
3.1作用:
1:让父子进程执行不相干的操作
2:能够替换进程地址空间段的源代码.text段
3:当前程序中调用另外一个程序
4:PID不变
3.2 分类
分类 | 函数 |
---|---|
字符串数组参数 | execv()、execvp()、execve() |
可变参数 | execle()、execlp()、execl() |
3.3exec函数组名字规律
字符 | 含义 |
---|---|
v | 第二个参数是数组 |
l | 第二个参数之后是变参 |
p | 第一个参数是文件名 |
e | 最后一个参数是环境变量 |
3.4返回值
返回值 | 含义 |
---|---|
-1 | 失败 |
不返回 | 成功 |
3.5实例
3.5.1excel
占位:可以随便写
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/stat.h>
int main(int argc,char *argv[]){
int i;
for(i=0;i<8;i++){
printf(" parent:%d\n",i);
}
int pid=fork();
if(pid==0){
//只是程序使用的子进程的地址覆盖
execl("/bin/ls","666","-l",NULL);
}
//所以子进程不执行下面操作
for(i=0;i<3;i++){
printf(" --------i:%d\n",i);
}
return 0;
}
3.5.2excep
不用写命令路径,只需要写命令 系统直接在SPATH环境变量中找
excel("ps","ps","aux",NULL);
4 系统函数int system(Shell字符串)
4.1返回值
返回值 | 含义 |
---|---|
-1 | 失败 |
127 | 无法启动shell来运行 |
其他 | 命令退出码 |
4.2 特点
一次调用,一次返回
4.3示例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc,char** argv){
printf("PID:%d\n",getpid());
system("sleep 3&");
printf("PID:%d\n",getpid());
}
4.4本质
shell执行命令/程序
5结束进程
5.1分类
方式 | 说明 |
---|---|
1 main函数退出 | 只能用在main函数内 |
2 调用exit()函数 | 一般用在main函数以外的函数 |
3 调用_exit()函数 | 一般用来结束子进程 |
4 调用abort()函数 | 一般用来异常退出 |
5 信号终止 | 终止其他进程 |
5.2示例
return退出
#include <stdio.h>
#include <unistd.h>
int main(){
printf("PID:%d,PPID:%d\n",getpid(),getppid());
return 100;
}
exit()/abort()退出
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
printf("PID:%d,PPID:%d\n",getpid(),getppid());
//exit(EXIT_FAILURE);
abort();
}
作者:jdzhangxin
链接:https://www.jianshu.com/p/011bd63208ef
来源:简书
6休眠进程
int sleep(unsigned int secs)
6.1参数
secs指定休眠的秒数,-1表示永久休眠
6.2返回值
未休眠的秒数
6.3特性
如果没有信号中断,休眠指定秒数返回0,否则马上返回未休眠的秒数。
示例:电子时钟
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <strings.h>
int main(){
int i = 0;
for(;;){
time_t t;
time(&t);
struct tm* ptm = gmtime(&t);
char buf[BUFSIZ];
bzero(buf,BUFSIZ);
strftime(buf,BUFSIZ,"%P %T",ptm);
printf("\r%s",buf);
fflush(stdout);
sleep(1);
}
}
作者:jdzhangxin
链接:https://www.jianshu.com/p/011bd63208ef
来源:简书
暂停int pause()
返回值
总是-1
特性
如果程序没有处理信号,直接中断,执行默认信号处理,程序后续代码不再执行。
如果程序存在信号处理,执行信号处理后,执行后续代码。
等待信号
No. 快捷键 信号 说明
1 Ctrl+C SIGINT 中断
2 Ctrl+Z SIGTSTP 终端的停止信号
示例
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void test(int sig){
printf("revc a signal%d",sig);
}
int main(){
signal(SIGINT,test);
printf("before pause\n");
pause();
printf("after pause\n");
}
作者:jdzhangxin
链接:https://www.jianshu.com/p/011bd63208ef
来源:简书
7回收进程
7.1特殊进程
概念 | 出现条件 | 导致结果 | 是否有害 | 原因 |
---|---|---|---|---|
1 孤儿进程 | 父进程先于子进程退出 | init进程作为新的父进程 | 无害 | 进程结束后 能够释放用户区空间释放不了pcb 必须有父进程释放 |
2 僵尸进程 | 子进程退出,父进程没有获取子进程的状态信息 | 调用wait或waitpid | 有害,避免出现僵尸进程 | 父进程没有释放进程的pcb ,孩子就变成了僵尸进程 |
//孤儿进程
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/stat.h>
#include<sys/types.h>
int main(int argc,char *argv[]){
int pid=fork();
if(pid==0){
sleep(1);
printf("chlid pid=%d,ppid=%d\n",getpid(),getppid());
}else{
printf("==========parent\n");
}
return 0;
}
//僵尸进程
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/stat.h>
#include<sys/types.h>
int main(int argc,char *argv[]){
int pid=fork();
if(pid==0){
sleep(1);
printf("chlid pid=%d,ppid=%d\n",getpid(),getppid());
}else{
while(1){
printf("==========parent\n");
}
}
return 0;
}
kill -9 无法杀死僵尸进程 所以得杀死父进程
7.2阻塞函数wait
1:pid_t wait(int* status):等价pid_t waitpid(-1,stauts,0)每次调用只能回收一个
7.2.1参数
参数 | 含义 | 说明 |
---|---|---|
pid | 等待的进程 | <-1:等待进程组为pid的所有进程;-1: 等待任何子进程;0:等待同组的进程;>0:进程为pid 的子进程 |
status | 回收的子进程结束状态 | 判断正常结束:使用WIFEXITED(status);判断异常结束使用WIFSIGNALED(status);判断暂停使用WIFSTOPPED(status) |
options | 选项 | WNOHANG若子进程没有结束,返回0,不予以等待;若子进程结束,返回该子进程的ID。WUNTRACED若子进程进入暂停状态,则马上返回,但子进程的结束状态不予以理会。 |
7.2.2返回值
返回值 | 含义 |
---|---|
-1 | 失败 |
其他 | 等待的PID |
7.2.3正常结束:WIFEXITED(status)
参数 | 含义 |
---|---|
非0 | 正常结束子进程0 |
WEXITSTATUS(status)取得子**进程exit()**返回的结束代码,一般会先用WIFEXITED来判断是否正常结束才能使用此宏
7.2.4异常结束:WIFSIGNALED(status)
参数 | 含义 |
---|---|
非0 | 异常结束子进程 |
2 0 | 非异常结束子进程 |
WTERMSIG(status)取得子进程因信号而中止的信号代码
一般会先用 WIFSIGNALED 来判断后才使用此宏
7.2.5暂停:WIFSTOPPED(status)
参数 | 含义 |
---|---|
非0 | 暂停结束子进程 |
0 | 非暂停结束子进程 |
WSTOPSIG(status)取得引发子进程暂停的信号代码
一般会先用 WIFSTOPPED 来判断后才使用此宏。
7.2.6示例
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/wait.h>
int main(int argc,char *argv[]){
int pid=fork();
if(pid==0){
sleep(1);
printf("chlid pid=%d,ppid=%d\n",getpid(),getppid());
}else{
printf("parent pid=%d,ppid=%d\n",getpid(),getppid());
//
int status;
pid_t wpid=wait(&status);
if(WIFEXITED(status)){
printf("exit value %d\n",WIFEXITED(status));
}
if(WIFSIGNALED(status)){
printf("exit by signal %d\n",WIFSIGNALED(status));
}
printf("dead_child pid=%d\n",wpid);
}
return 0;
}
结果: