进程:程序执行一次的过程
进程和程序的区别:
程序是静态的二进制有序集合,进程是动态的执行过程
程序只有文本和数据,进程除了文本和数据还有系统级别的数据
进程是资源分配的最小单位
进程结构、类型和运行状态
PID唯一地标识了一个进程
Linux中的进程包含三个段:
数据段:存放的是全局变量、常数以及动态数据分配的数据空间(如malloc函数取得的空间等)
正文段:存放的是程序中的代码
堆栈段:存放的是函数的返回地址、函数的参数以及程序中的局部变量
Linux中的进程类型:
交互进程:该类进程是由shell控制和运行的。交互进程既可以在前台运行,也可以在后台运行
批处理进程:该类进程不属于某个终端,他被提交到一个队列中以便顺序执行。
守护进程:该类进程在后台运行,他一般在Linux启动时开始执行,系统关闭才结束。
一般学习的是交互进程,守护进程就是后台平常不显示的进程,批处理不管
进程的运行状态:
运行态:此时进程正在运行或者准备运行
等待态:此时进程在等待一个事件的发生或某种系统资源
停止态:此时进程已被终止
死亡态:这是一个已终止的进程,但还在进程向量数组中占用一个task_struct结构
1.创建进程(fork、vfork)
注意fork和vfork的区别
pid_t fork(void);
功能:创建子进程
返回值:成功返回等于或者大于0的数,失败返回-1
子进程返回0,父进程返回子进程ID号
pid_t vfork(void);
功能:创建子进程
返回值:成功返回等于或者大于0的数,失败返回-1
子进程返回0,父进程返回子进程ID号
注:只能先运行子进程,并且子进程结束了(exit或者exec)才能运行父进程
fork 逻辑:
在运行父进程时,会将所有的父进程的内容拷贝到子进程中,
到生孩子那一步,pc指向下一个指令,子进程中pc也是如此,故不会嵌套的创建子节点
vfork 逻辑:(写时拷贝)
子进程暂时先占用父进程的内存来使用,父进程不能使用该内存,
只有子进程用exit或者exec退出时,父进程才能使用改内存,子进程调用exec
即子进程去执行一个新的进程,指向了一个新的内存空间,父进程可以使用原空间了
fork-eg:
int main()
{
pid_t pid = fork();
if(pid < 0)
{
perror("fork");
return -1;
}
else if(pid == 0)
printf("I am child\n"); //child
else
printf("I am father\n"); //parent
}
vfork-eg:
int main()
{
pid_t pid = vfork();
if(pid < 0)
{
perror("vf");
return -1;
}
else if(pid == 0)
{
printf("I am child\n"); //child
//return 0; //return 0;都没用,要用exit函数退出
}
else
printf("I am father\n"); //parent
}
2.进程退出(exit、_exit)
void exit(int status);
功能:让当前进程退出
status:进程退出时想要传递的值(传递给回收者)
void _exit(int status);
功能:让当前进程退出
status:进程退出时想要传递的值(传递给回收者)
_exit进程退出时不清空IO缓冲区,exit退出时要清空
eg:
int main()
{
printf("ikun");
_exit(0);
}------------>不会打印ikun,没有将缓冲区的内容吐出来
3.exec函数族(execl)
exec函数族提供了一种在进程中启动另一个程序的执行的方法。
它可以根据指定的文件名和目录名找到该文件,并用它取代原调用进程的数据段、代码段和堆栈段。
在执行完之后,原调用进程的内容除了进程号外,其他全部被替换了
eg:
int main()
{
int ret = execl("/bin/ls", "sh", NULL);
if(ret < 0)
{
perror("execl");
return -1;
}
}
gcc后运行./a.out 即在a.out进程里调用ls进程
练习:父进程是打印当前时间,子进程是打印一个菱形
父进程是打印当前时间,子进程是打印一个菱形,可执行程序为app
//app是打印一个菱形的程序
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
time_t tm; //打印当前时间的代码
struct tm *tp;
time(&tm);
tp=localtime(&tm);
//创建一个子进程
pid_t pid=vfork();
if(pid<0){
perror("vfork");
return -1;
}
else if(pid==0){
execl("app","./",NULL); //子进程为运行app,运行完退出
//exit(0);
//直接退出子进程
}
//如果没有exec或exit退出子进程,则无法使用父进程
else //子进程没退出,父进程使用了,则会出现段错误
printf("%d-%d-%d %d:%d:%d\n",
tp->tm_year+1900,tp->tm_mon+1,tp->tm_mday,
tp->tm_hour,tp->tm_min,tp->tm_sec); //父进程
return 0;
}
4.回收进程
某个进程退出后会变成僵尸态,如果不回收这个进程,那么会一直占用系统资源
#include <sys/wait.h>
pid_t wait(int *wstatus);
功能:阻塞等待回收子进程
返回值:成功返回回收到的进程ID,失败返回-1
wstatus:保存exit的值以及子进程退出状态是否正常
pid_t waitpid(pid_t pid, int *wstatus, int options);
功能:回收子进程(可以非阻塞,也可以指定要回收谁)
返回值:成功返回进程ID,失败返回-1
pid:用于指定要回收的进程号
-1:表示任意子进程
>0:表示子进程号
wstatus:保存进程退出值以及状态
options:阻塞或者非阻塞的方式
WNOHANG:非阻塞
0:阻塞
回收子进程由父进程回收,写进父进程里
wstatus组成:2字节空+1字节的退出信息+1字节的退出状态
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t pid = fork();
if(pid < 0)
{
perror("fork");
return -1;
}
else if(pid == 0)
{
while(1);
char *p = NULL;
*p = 10; //段错误
exit(23);
}else
{
int status;
//wait(&status);
waitpid(-1, &status, WNOHANG);
printf("wait success\n");
printf("child process exit type = %d\n", status & 0x7f);
//退出状态
printf("child process exit val = %d\n", (status >> 8) & 0xff);
//退出信息
}
}
----->结果 type=11 (段错误号) val=0
如果正常退出,注释16、17、18行,type = 0,val = 23
5.守护进程
1.创建子进程,并且退出父进程
pid_t pid=fork();
if(pid>0)
exit(0);
2.创建新会话
pid_t setsid(void);
3.更改工作目录
int chdir(const char*path);
4.重设文件掩码
mode_t umask(mode_t mask);
5. 关闭掉从父进程继承过来的所有文件描述符
循环close
for(int i=0;i<getdtablesize();i++)
close(i);
6.练习:将在一个文件里循环打印当前时间的功能,放进守护进程
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
pid_t pid=fork();
if(pid<0)
{
perror("fork");
return -1;
}
else if(pid>0)
{
exit(0); // 1.关闭父进程
}
else
{
setsid(); // 2.创建新会话
chdir("/.tmp"); // 3.更改工作目录
umask(0); // 4.重设文件掩码
for(int i=0;i<getdtablesize();i++) //关闭父进程继承过来的所有的文件描述符
close(i);
}
int id=open("1.txt",O_WRONLY | O_CREAT,0777);
time_t tm;
while(1)
{
time(&tm);
dprintf(id,"%s\n",ctime(&tm));
sleep(1);
}
return 0;
}
参考:https://blog.csdn.net/jianchi88/article/details/6985326