随笔 复习 连接池 线程池大概 守护进程
连接池实现思路
class ConnectPool
{
public:
ConnectPool(int number)
{
for(int i=0;i<=number;i++)
{
int fd = socket(); // 创建通信的fd
conect(); // 连接服务器
m_list.push(fd);//往容器中存储 链接
}
}
//提取
int getConnect()
{
if(m_list.size()>0)
{
int fd=m_list.head();
m_list.pop();
return fd;
}
return -1;
}
//放回
void putConnect(int fd,bool isvaild)
{
m_list.push(fd);
}
~ConnectPool();
private:
queue<int> m_list;
}
线程池
线程池
优点:
可以回收用完的线程
不需要重复频繁的创建销毁线程
根本:多个线程的一个集合, 可以回收用完的线程
设计思路
管理者->1
工作者->N个
管理者
检测工作线程是否多或少 以及状态
工作者
处理业务逻辑
需要任务队列
存储任务->唤醒阻塞->条件变量
分发任务 没有任务阻塞
线程个数 ->业务逻辑
密集型 需要很多cpu时间 线程个数=当前电脑的核心数
IO操作
线程个数=2倍核心cpu数
代码核心
逻辑图
6.守护进程
生产周期长,独立于控制终端,周期执行某些任务
Linux 的大多数服务器就是用守护进程实现的。比如,Internet 服务器 inetd,Web 服务器 httpd 等。
1.守护进程模型
创建子进程,父进程退出(必须)
所有工作在子进程中进行形式上脱离了控制终端
2.在子进程中创建新会话(必须)
setsid()函数
使子进程完全独立出来,脱离控制
3.改变当前目录为根目录(不是必须)
chdir()函数
防止占用可卸载的文件系统
也可以换成其它路径
4.重设文件权限掩码(不是必须)
umask()函数
防止继承的文件创建屏蔽字拒绝某些权限
增加守护进程灵活性
掩码更改 umask () ->例如现在掩码是0002 我们设置权限777->与操作掩码0002 ->0775
5.关闭文件描述符(不是必须)
继承的打开文件不会用到,浪费系统资源,无法卸载
6.开始执行守护进程核心工作(必须)
守护进程退出处理程序模型
2.守护进程示例代码
[//守护进程模型
//1.创建子进程 父进程退出--成为孤儿进程 但是终端关闭还是会被回收
pid_t pid = -1;
int ret=-1;
pid = fork();
if (pid == -1)
{
perror("fork");
}
if (pid > 0)
{
exit(0);
}
///2.创建会话 脱离终端 --成为新会话领导者 --终端关闭不再被结束
pid=setsid();
if (-1 == pid)
{
perror("setsid");
}
//3.改变工作目录 脱离父进程的工作目录和文件系统
ret = chdir("/");
if (-1 == ret)
{
perror("chdir");
return -1;
}
//4.设置权限掩码 控制守护进程创建文件时的默认权限,以确保所创建的文件不会对系统造成安全隐患
/*
这段代码关闭了文件描述符0(标准输入)、1(标准输出)和2(标准错误),通常是作为守护进程初始化的一部分。关闭这些文件描述符主要是为了脱离与父进程的标准输入、输出和错误流的关联,从而使守护进程不会受到终端的影响。
具体来说,关闭这些文件描述符可以达到以下目的:
脱离终端:关闭标准输入、输出和错误流可以确保守护进程不再与任何终端相关联,从而使其可以在后台独立运行,而不会受到终端的影响。
避免意外输入输出:关闭标准输入、输出和错误流可以防止守护进程意外地从终端接收输入或向终端输出信息,从而避免不必要的交互或输出干扰。
规范化输入输出:在守护进程中,通常会将标准输入重定向到 /dev/null(空设备,即丢弃所有输入)、标准输出和标准错误重定向到日志文件或其他适当的位置,以便记录守护进程的运行日志和错误信息。
总的来说,关闭标准输入、输出和错误流是守护进程初始化时的常见做法,旨在确保守护进程能够独立地在后台运行,并且能够规范地处理输入输出。
*/
umask(0);
//5.关闭文件描述符
close(0);
close(1);
close(2);
//6.核心代码
while (1)
{
system("date >> /tmp/txt.log");
sleep(2);
}
return 0;
]()