Linux系统编程——进程(函数)
回调函数:
atexit()
原型: int atexit(void (*function)(void));
功能: 注册进程退出前执行的函数
参数: @function 函数指针,指向void返回值void参数的函数指针
返回值 成功 返回0
失败 返回非0
当注册调用exit或者由main函数执行return时,所有用atexit注册的退出函数,将会由注册时顺序被调用
代码示例:
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
FILE* fp;
char* p;
void clean()
{
printf("clean fun ,p is %s\n", p);
fclose(fp);
free(p);
}
int main(int argc, char** argv)
{
atexit(clean);
fp = fopen("1.txt", "r");
p = malloc(50);
strcpy(p, "hello");
printf("process will end..\n");
return 0;
}
进程空间的回收
wait() / waitpid()
原型: pit_t wait(int *status); //阻塞回收(等待子进程结束再回收)
功能: 该函数可以阻塞等待任意子进程退出并回收该进程的状态(一次回收一个子进程)
//一般用于父进程回收子进程的状态
参数: @status 进程退出时候的状态
//如果不关心其退出状态一般用NULL表示
//如果要回收进程退出状态(正常退出 / 异常退出),则用WEXITSTATUS回收
返回值 成功 返回回收的子进程的pid
失败 返回-1
1)如果所有的子进程都在运行,在阻塞
2)如果一个子进程终止,正在等待的父进程则获得终止状态,获得子进程的状态后,立刻返回。
3)如果没有子进程,则立即出错退出。
waitpid(-1, status, 0) = wait(status)
原型: pid_t waitpid(pid_t pid, int status); //非阻塞回收
功能: 用于等待特定子进程的状态变化
参数: @pid
@status
int status;
waitpid(pid, &status, 0);// 检查宏:
WIFEXITED(status) // 子进程正常退出?
WEXITSTATUS(status) // 获取退出状态码
WIFSIGNALED(status) // 子进程被信号终止?
WTERMSIG(status) // 获取终止信号编号
WIFSTOPPED(status) // 子进程是否被暂停?
WSTOPSIG(status) // 获取暂停信号编号
返回值
代码示例:
//<1>完整使用示例
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char **argv)
{
pid_t pid = fork();
if (pid > 0)
{
printf("father pid:%d, child pid:%d\n", getpid(), pid);
int status;
while (1)
{
//非阻塞回收
pid_t recycle_pid = waitpid(pid, &status, WNOHANG);
if (pid == recycle_pid)
{
printf("recycle_pid:%d\n", recycle_pid);
//子进程正常结束
if (WIFEXITED(status))
{
printf("child ret value is %d\n", WEXITSTATUS(status));
}
else if (WIFSIGNALED(status))
{
printf("child unnormal,signal is %d\n", WTERMSIG(status));
}
break;
}
else if (0 == recycle_pid) //子进程未结束
{
printf("子进程未结束...\n");
usleep(1000*500);//0.5s
}
else
{
printf("waitpid error...\n");
break;
}
}
}
else if (0 == pid)
{
int i = 10;
while (i--)
{
printf("I'm processing....\n");
sleep(1);
}
exit(20);
}
else
{
perror("fork error\n");
return 1;
}
return 0;
}
//<2>非阻塞回收制定进程
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
int id = 2;
int n = 0;
printf("n = :");
scanf("%d", &n);
pid_t pid[5] = {0};
//创建5个子进程
while (n--)
{
pid[n] = fork();
if (pid[n] > 0)
{
continue;
}
else if (0 == pid[n])
{
printf("%d pid:%d\n",n, getpid());
sleep(rand() % 5+1);
exit(20);
}
else
{
perror("fork err...\n");
return 1;
}
}
//回收id = 2的进程
while (1)
{
pid_t recycle_pid = waitpid(pid[id-1], NULL, WNOHANG);
if(pid[id-1] == recycle_pid) //回收成功,相当于recycle_pid > 0
{
printf("recycle_pid: %d success\n",recycle_pid);
break;
}
else if(0 == recycle_pid)
{
}
else //recycle_pid<0,回收失败
{
printf("recycle_pid failure....\n");
}
}
return 0;
}
exec族
功能:用fork创建子进程后执行的是和父进程相同的程序 (但有可能执行不同的代码分支)
子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的
用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建
新进程,所以调用exec前后该进程的id并未改变。
其实有六种以exec开头的函数,统称exec函数:
头文件:#include <unistd.h>
!!!调用非系统可执行程序,第一个参数都传路径+文件名
原型: int execl(const char *path, const char *arg, ...,/* (char *) NULL */); // l :list
参数: @path 可执行程序的路径
@arg 参数 [字符串的形式] 列表,可以有多个
@NULL 参数结束标志(不能省)
示例:execl("/bin/ls", "ls","-a","-l","--color == auto",NULL);
原型: int execlp(const char *file, const char *arg, ...,/* (char *) NULL */); //p: PATH
参数: @file 文件名(在系统路径$PATH 下可以找到) //命令:echo $PATH
@arg 参数 [字符串的形式] 列表,可以有多个
@NULL 参数结束标志(不能省)
示例:
PATH 系统环境变量 查看命令:echo $PATH
execlp("ls", "ls", "-a", "-l", "--color=auto", NULL);
原型: int execv(const char *path, char *const argv[],NULL); // v:vector(数组)
参数: @path 可执行程序的路径
@arg 参数 [字符串的形式] 列表,可以有多个
@NULL 参数结束标志(不能省)
示例:
char *const args[] = {"cp", "11exec.c", "cp.txt",NULL};
execv("/bin/cp", args);
原型: int execvp(const char *file, char *const argv[],NULL); // vp: vector path
参数: @file 文件名(在系统路径$PATH 下可以找到) //命令:echo $PATH
@arg 参数 [字符串的形式] 列表,可以有多个
@NULL 参数结束标志(不能省)
示例:
char *const args[] = {"cat","11exec.c",NULL};
execvp(args[0], args);
更多推荐
所有评论(0)