方法教程 | C++爬虫:进程 · 全家桶
Posted 爬小虫联盟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了方法教程 | C++爬虫:进程 · 全家桶相关的知识,希望对你有一定的参考价值。
“初见进程,先查一下户口
3.1、fork
3.2、exec族
3.3、wait/waitpid
进程的产生方式:
①进程环境
②进程状态
③进程原语
来个联系方式吧,进程间通信
进程间同步
家庭关系如何?(进程间关系)
①进程组
②会话
守护者
程序、进程与线程的区分。”
①进程环境
进程控制块PCB:就是进程在操作系统中的“户口”,具体实现是 task_struct数据结构:
1.状态信息,例如这个进程处于可执行状态,休眠,挂起等。
2.性质,由于unix有很多变种,进程有自己独特的性质。
3.资源,资源的链接比如内存,还有资源的限制和权限等。
4.组织,例如按照家族关系建立起来的树(父进程,子进程等)
②进程状态
运行状态R(TASK_RUNNING)
可中断睡眠状态S(TASK_INTERRUPTIBLE)
不可中断睡眠状态D(TASK_UNINTERRUPTIBLE)
暂停状态T(TASK_STOPPED或TASK_TRACED)
僵死状态Z(EXIT_ZOMBIE)
退出状态X(EXIT_DEAD)
③进程原语
3.1、fork
#include <unistd.h>
pid_t fork(void);
父进程中返回子进程id (就是大于0的意思)
子进程返回0
读时共享写时复制,可保高效
pid_t getpid(void); //获取进程ID
pid_t getppid(void); //获取父进程ID
uid_t getuid(void);//返回实际用户ID
uid_t geteuid(void);//返回有效用户ID
进程的产生方式:
(1)复制父进程的系统环境(放心,只要是你开的进程,肯定有父进程)
(2)在内核中建立进程结构
(3)将结构插入到进程列表,便于维护
(4)分配资源给该进程
(5)复制父进程的内存映射消息
(6)管理文件描述符和链接点
(7)通知父进程
3.2、exec族
fork子进程是为了执行新程序(fork创建了子进程后,子进程和父进程同时被OS调度执行,因此子进程可以单独的执行一个程序,这个程序宏观上将会和父进程程序同时进行)
可以直接在子进程的if中写入新程序打代码。但这样不够灵活,因为我们只能把子进程程序的源代码贴过来执行(必须知道源代码,而且源代码太长了也不好控制)
使用exec族函数运行新的可执行程序。exec族函数可以直接把一个编译好的可执行程序直接加载运行
有了exec族函数后,典型打父子进程程序是这样的:子进程需要运行的程序被单独编写、单独编译链接成一个可执行程序(hello)。主进程为父进程,fork创建了子进程后在子进程中exec来执行hello,达到父子进程分别做不同程序同时(宏观上)运行的效果。
int execve(const char *path,char *const argv[],char *const envp[]);//这个是真正的系统调用
//以下的函数最后都是调用这个函数
int execl(const char *path,char *const argv,···);
int execlp(const char *file,char *const argv,···);
int execle(const char *path,char *const argv,···· ,char *const envp[]);
int execv(const char *path,char *const argv[]);
int execvp(const char *file,char *const argv,);
int main(void)
{
pid_t pid;
if((pid = fork()) < 0)
{
perror("fork");
exit(1);
}
else if(pid == 0)
{
/* child */
execl("/bin/ls", "ls", "-l", "-a",NULL);
}
else
{
printf("parent, child id = %d.\n",pid);
}
return 0;
}
3.3、wait/waitpid
这里几个概念:
僵尸进程:子进程退出,父进程没有及时回收,子进程成为僵尸进程
孤儿进程:父进程退出,而子进程没有退出,子进程成为孤儿进程
init进程:1号进程,负责收留孤儿进程,成为他们的父进程
有5种方式终止进程:
(1)main返回
(2)调用exit
(3)调用_exit
(4)调用abort(给自己发送异常终止信号)
(5)由一个信号终止
pid_t wait(int *status);
//这里的status为一个整形指针,是该子进程的返回状态。若该指针不为空,则可以通过该指针获取子进程退出时的状态。
pid_t waitpid(pid_t pid,int *status,int options);
// pid是进程号
/*
<-1 回收指定进程组内的任意子进程
-1 回收任意子进程
0 回收和当前waitpid调用一个组的所有子进程
>0 回收指定ID的子进程
*/
//options:
/*
WNOHANG:强制回收,不阻塞。
WUNTRANCED:一般用上面那个
*/
来个联系方式吧,进程间通信
()接收方发送请求后,内核按照标识取出消息。
()消息队列是一种完全异步的通信方式。
想要进程的联系方式?点这里
进程间同步
家庭关系如何?(进程间关系)
①进程组
//获取当前进程组组ID
pid_t getpgid(pid_t pid);
pid_t getpgrp(void);
几个概念:
组长进程:进程ID号等于组ID。
组长进程可以创建一个进程组,创建该进程组中的进程。
只要进程中有一个进程存在,进程组就存在,与组长进程是否终止无关。
//一个进程可以为自己或子进程设置进程组ID
int setpgid(pid_t pid,pid_t pgid);
//非root进程只能改变自己创建的子进程,或有权限操作的进程
②会话
pid_t setsid(void);
1、调用进程不能是进程组组长,该进程变成新会话的首进程。
2、该进程成为一个新进程组的组长进程。
3、需要有root权限(ubunt不需要)
4、新会话丢弃原有控制终端,该会话没有控制终端。
5、建立新会话时,先用fork,然后父进程终止,子进程调用
pid_t getsid(pid_t pid);
用于查看当前进程的会话ID
int main()
{
pid_t pid;
pid = fork();
if(pid == 0)
{
//打印:
getpid();//进程ID
getpgid(0);//组ID
getsid(0);//会话ID
sleep(10);
setsid();//子进程设为会话组长
//子进程非组长进程,故其成为新会话首进程,且成为组长进程。
//该进程ID即为会话进程ID
//再打印一遍
getpid();//进程ID
getpgid(0);//组ID
getsid(0);//会话ID
}
}
程序、进程与线程的区分
(1)进程是动态的,程序是静态的。
(2)一个进程只能对应一个程序,而一个程序可以对应多个进程。
这是保存下来的进程方法,如有不足之处或更多技巧,欢迎指教补充。愿本文的分享对您之后爬虫有所帮助。谢谢~
编辑排版:筱筱 原创:看,未来
以上是关于方法教程 | C++爬虫:进程 · 全家桶的主要内容,如果未能解决你的问题,请参考以下文章
阿里P8推荐马士兵教育2021最新Spring源码全家桶教程100集