Linux——多线程(五)

news/2024/9/13 22:42:02/ 标签: linux, c++, xcode

1.线程池

1.1初期框架

thread.hpp

#include<iostream>
#include <string>
#include <unistd.h>
#include <functional>
#include <pthread.h>namespace ThreadModule
{using func_t = std::function<void()>;class Thread{public:void Excute(){_func();}public:Thread(func_t func, std::string name="none-name"): _func(func), _threadname(name), _stop(true){}static void *threadroutine(void *args) //注意:类成员函数,形参是有this指针的{Thread *self = static_cast<Thread *>(args);self->Excute();return nullptr;}bool Start(){int n = pthread_create(&_tid, nullptr, threadroutine, this);if(!n){_stop = false;return true;}else{return false;}}void Detach(){if(!_stop){pthread_detach(_tid);}}void Join(){if(!_stop){pthread_join(_tid, nullptr);}}std::string name(){return _threadname;}void Stop(){_stop = true;}~Thread() {}private:pthread_t _tid;//线程tidstd::string _threadname;//线程名字func_t _func;//线程所要执行的函数bool _stop;//判断线程是否停止};
}

 ThreadPool.hpp 

#include<vector>
#include<unistd.h>
#include<string>
#include<queue>
#include"Thread.hpp"using namespace ThreadModule;
const int g_thread_num = 3;//默认线程数
// 线程池->一批线程,一批任务,有任务push、有任务pop,本质是: 生产消费模型
template <typename T>
class ThreadPool
{
public:ThreadPool(int threadnum=g_thread_num)//构造函数:_threadnum(threadnum), _waitnum(0), _isrunning(false){pthread_mutex_init(&_mutex,nullptr);//初始化锁pthread_cond_init(&_cond,nullptr);//初始化条件变量}void Print(){while(true){std::cout<<"我是一个线程"<<std::endl;sleep(1);}}void InitThreadPool(){// 指向构建出所有的线程,并不启动for (int num = 0; num < _threadnum; num++){std::string name = "thread-" + std::to_string(num + 1);_threads.emplace_back(Print,name);//线程处理函数是Print,注意这里有问题}_isrunning = true;}void Start()//启动线程池{for(auto &thread:_threads){thread.Start();std::cout<<thread.name()<<"线程:启动成功"<<std::endl;}}void Wait(){for(auto &thread:_threads){thread.Join();}}// bool Enqueue(const T &t)// {// }~ThreadPool()//析构{pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}
private:int _threadnum;//线程的数量std::vector<Thread> _threads;//用vector来存线程std::queue<T> _task_queue;//任务队列pthread_mutex_t _mutex;//锁pthread_cond_t _cond;//条件变量int _waitnum;//有几个线程阻塞bool _isrunning;//判断线程池是否在运行
};

main.cc

#include <iostream>	
#include <string>
#include <memory>
#include "threadpool.hpp"	int main()
{std::unique_ptr<ThreadPool<int>> tp(new ThreadPool<int>()); tp->InitThreadPool();tp->Start();sleep(5);tp->Wait();return 0;
}

 

 此时会报错:无效使用非静态成员函数...

主要原因是成员函数包含this指针而thread.hpp中线程所要执行函数的参数为空:using func_t = std::function<void()>;,导致参数类型不匹配

有两种解决方法

 方法一:在Print函数前面加上static

    static void Print(){while(true){std::cout<<"我是一个线程"<<std::endl;sleep(1);}}

 

方法二:在初始化线程池时用bind绑定ThreadPool内部的Print方法,缺省地设置参数this,就是将this参数默认的绑定到Print方法上,这样一来就和thread.hpp中的参数匹配上了 

    void InitThreadPool(){// 指向构建出所有的线程,并不启动for (int num = 0; num < _threadnum; num++){std::string name = "thread-" + std::to_string(num + 1);//_threads.emplace_back(Print,name);//线程处理函数是Print_threads.emplace_back(std::bind(&ThreadPool::Print,this),name);}_isrunning = true;}

  也是成功运行

就算后面我们需要更改线程的参数
 那么也可以在初始化函数那里固定式的绑定参数了

不需要再去单独给线程设计参数对象了 

一个类的成员方法设计成另一个类的回调方法,常见的实现就是这种

类的成员方法也可以成为另一个类的回调方法,方便我们继续类级别的互相调用

 

1.2代码完善

 

接下来就是如何入队列以及我们的新线程应该做什么任务...

处理任务:每一个线程进来的时候都需要去任务队列中获取任务,所以我们首当其冲的就要对任务队列给它锁住

任务队列的加锁、解锁以及线程的等待与唤醒(条件变量)

private:void LockQueue(){pthread_mutex_lock(&_mutex);}void UnlockQueue(){pthread_mutex_unlock(&_mutex);}void ThreadSleep(){pthread_cond_wait(&_cond, &_mutex);}void ThreadWakeup(){pthread_cond_signal(&_cond);}void ThreadWakeupAll(){pthread_cond_broadcast(&_cond);}

 处理任务

    void HandlerTask(std::string name)//线程处理任务{while (true){//加锁LockQueue();//任务队列中不一定有数据,如果任务队列为空且线程池在跑,那么就阻塞住while(_task_queue.empty()&&_isrunning){_waitnum++;ThreadSleep();_waitnum--;}//如果任务队列是空的,然后线程池又退出了,那么就没必要运行了if(_task_queue.empty() && !_isrunning){UnlockQueue();std::cout<<name<<"quit..."<<std::endl;sleep(1);break;}//不论线程池有没有退出,走到这说明一定有任务 ->处理任务T t = _task_queue.front();_task_queue.pop();UnlockQueue();//解锁t();}}

 注意:这个任务是属于线程独占的任务,不能再任务队列的加锁、解锁之间处理

 入任务队列

如果线程阻塞等待的数量大于0,就唤醒一个线程

 

    bool Enqueue(const T &t){bool ret = false;LockQueue();if(_isrunning){_task_queue.push(t);if(_waitnum>0){ThreadWakeup();}ret = true;}UnlockQueue();return ret;}

threadpool.hpp

任务还没写,所以t()先注释掉

#include<iostream>
#include<vector>
#include<unistd.h>
#include<string>
#include<queue>
#include"LockGuard.hpp"
#include"Thread.hpp"using namespace ThreadModule;
const int g_thread_num = 3;//默认线程数
// 线程池->一批线程,一批任务,有任务push、有任务pop,本质是: 生产消费模型
template <typename T>
class ThreadPool
{
private:void LockQueue(){pthread_mutex_lock(&_mutex);}void UnlockQueue(){pthread_mutex_unlock(&_mutex);}void ThreadSleep(){pthread_cond_wait(&_cond, &_mutex);}void ThreadWakeup(){pthread_cond_signal(&_cond);}void ThreadWakeupAll(){pthread_cond_broadcast(&_cond);}
public:ThreadPool(int threadnum=g_thread_num)//构造函数:_threadnum(threadnum), _waitnum(0), _isrunning(false){pthread_mutex_init(&_mutex,nullptr);//初始化锁pthread_cond_init(&_cond,nullptr);//初始化条件变量}// static void Print()// {//     while(true)//     {//         std::cout<<"我是一个线程"<<std::endl;//         sleep(1);//     }// }// void Print(std::string name)// {//     while(true)//     {//         std::cout<<"我是一个线程,线程名是"<<name<<std::endl;//         sleep(1);//     }// }void InitThreadPool(){// 指向构建出所有的线程,并不启动for (int num = 0; num < _threadnum; num++){std::string name = "thread-" + std::to_string(num + 1);//_threads.emplace_back(Print,name);//线程处理函数是Print//_threads.emplace_back(std::bind(&ThreadPool::Print,this,std::placeholders::_1),name);_threads.emplace_back(std::bind(&ThreadPool::HandlerTask,this,std::placeholders::_1),name);}_isrunning = true;}void Start()//启动线程池{for(auto &thread:_threads){thread.Start();std::cout<<thread.name()<<"线程:启动成功"<<std::endl;}}void HandlerTask(std::string name)//线程处理任务{while (true){//加锁LockQueue();//任务队列中不一定有数据,如果任务队列为空且线程池在跑,那么就阻塞住while(_task_queue.empty()&&_isrunning){_waitnum++;std::cout<<name<<"线程阻塞中..."<<std::endl;ThreadSleep();_waitnum--;}//如果任务队列是空的,然后线程池又退出了,那么就没必要运行了if(_task_queue.empty() && !_isrunning){UnlockQueue();std::cout<<name<<"quit..."<<std::endl;sleep(1);break;}//不论线程池有没有退出,走到这说明一定有任务 ->处理任务T t = _task_queue.front();_task_queue.pop();UnlockQueue();//解锁//t();}}void Stop(){LockQueue();_isrunning = false;ThreadWakeupAll();UnlockQueue();        }void Wait(){for(auto &thread:_threads){thread.Join();}}bool Enqueue(const T &t){bool ret = false;LockQueue();if(_isrunning){_task_queue.push(t);if(_waitnum>0){ThreadWakeup();}ret = true;}UnlockQueue();return ret;}~ThreadPool()//析构{pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}
private:int _threadnum;//线程的数量std::vector<Thread> _threads;//用vector来存线程std::queue<T> _task_queue;//任务队列pthread_mutex_t _mutex;//锁pthread_cond_t _cond;//条件变量int _waitnum;bool _isrunning;//判断线程池是否在运行
};

 main.cc

#include <iostream>	
#include <string>
#include <memory>
#include "Task.hpp"
#include "threadpool.hpp"	int main()
{std::unique_ptr<ThreadPool<int>> tp(new ThreadPool<int>()); tp->InitThreadPool();tp->Start();sleep(2);tp->Stop();tp->Wait();return 0;
}

 

2.加上日志与任务

 LOG.hpp(日志)

#pragma once
#include <iostream>
#include <fstream>
#include <cstdio>
#include <string>
#include <ctime>
#include <cstdarg>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include"LockGuard.hpp"
bool gIsSave = false;
const std::string logname = "log.txt";// 1. 日志是有等级的
enum Level
{DEBUG = 0,INFO,WARNING,ERROR,FATAL
};
void SaveFile(const std::string &filename, const std::string &message)
{std::ofstream out(filename, std::ios::app);if (!out.is_open()){return;}out << message;out.close();
}
std::string LevelToString(int level)
{switch (level){case DEBUG:return "Debug";case INFO:return "Info";case WARNING:return "Warning";case ERROR:return "Error";case FATAL:return "Fatal";default:return "Unknown";}
}std::string GetTimeString()
{time_t curr_time = time(nullptr);struct tm *format_time = localtime(&curr_time);if (format_time == nullptr)return "None";char time_buffer[1024];snprintf(time_buffer, sizeof(time_buffer), "%d-%d-%d %d:%d:%d",format_time->tm_year + 1900,format_time->tm_mon + 1,format_time->tm_mday,format_time->tm_hour,format_time->tm_min,format_time->tm_sec);return time_buffer;
}pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
// 日志是有格式的
// 日志等级 时间 代码所在的文件名/行数 日志的内容
void LogMessage(std::string filename, int line,bool issave,int level, const char *format, ...)
{std::string levelstr = LevelToString(level);std::string timestr = GetTimeString();pid_t selfid = getpid();char buffer[1024];va_list arg;va_start(arg, format);vsnprintf(buffer, sizeof(buffer), format, arg);va_end(arg);std::string message = "[" + timestr + "]" + "[" + levelstr + "]" +"[" + std::to_string(selfid) + "]" +"[" + filename + "]" + "[" + std::to_string(line) + "] " + buffer + "\n";LockGuard lockguard(&lock);if (!issave){std::cout << message;}else{SaveFile(logname, message);}
}
#define LOG(level, format, ...)                                                \do                                                                         \{                                                                          \LogMessage(__FILE__, __LINE__, gIsSave, level, format, ##__VA_ARGS__); \} while (0)

 LockGuard.hpp

#ifndef __LOCK_GUARD_HPP__
#define __LOCK_GUARD_HPP__#include <iostream>
#include <pthread.h>class LockGuard
{
public:LockGuard(pthread_mutex_t *mutex):_mutex(mutex){pthread_mutex_lock(_mutex); // 构造加锁}~LockGuard(){pthread_mutex_unlock(_mutex);}
private:pthread_mutex_t *_mutex;
};#endif

threadpool.hpp

#include<iostream>
#include<vector>
#include<unistd.h>
#include<string>
#include<queue>	
#include"LOG.hpp"
#include"LockGuard.hpp"
#include"Thread.hpp"using namespace ThreadModule;
const int g_thread_num = 3;//默认线程数
// 线程池->一批线程,一批任务,有任务push、有任务pop,本质是: 生产消费模型
template <typename T>
class ThreadPool
{
private:void LockQueue(){pthread_mutex_lock(&_mutex);}void UnlockQueue(){pthread_mutex_unlock(&_mutex);}void ThreadSleep(){pthread_cond_wait(&_cond, &_mutex);}void ThreadWakeup(){pthread_cond_signal(&_cond);}void ThreadWakeupAll(){pthread_cond_broadcast(&_cond);}
public:ThreadPool(int threadnum=g_thread_num)//构造函数:_threadnum(threadnum), _waitnum(0), _isrunning(false){pthread_mutex_init(&_mutex,nullptr);//初始化锁pthread_cond_init(&_cond,nullptr);//初始化条件变量LOG(INFO, "线程池构造成功");}// static void Print()// {//     while(true)//     {//         std::cout<<"我是一个线程"<<std::endl;//         sleep(1);//     }// }// void Print(std::string name)// {//     while(true)//     {//         std::cout<<"我是一个线程,线程名是"<<name<<std::endl;//         sleep(1);//     }// }void InitThreadPool(){// 指向构建出所有的线程,并不启动for (int num = 0; num < _threadnum; num++){std::string name = "thread-" + std::to_string(num + 1);//_threads.emplace_back(Print,name);//线程处理函数是Print//_threads.emplace_back(std::bind(&ThreadPool::Print,this,std::placeholders::_1),name);_threads.emplace_back(std::bind(&ThreadPool::HandlerTask,this,std::placeholders::_1),name);LOG(INFO, "线程 %s 初始化成功", name.c_str());}_isrunning = true;}void Start()//启动线程池{for(auto &thread:_threads){thread.Start();std::cout<<thread.name()<<"线程:启动成功"<<std::endl;}}void HandlerTask(std::string name)//线程处理任务{LOG(INFO, "%s 正在运行...", name.c_str());while (true){//加锁LockQueue();//任务队列中不一定有数据,如果任务队列为空且线程池在跑,那么就阻塞住while(_task_queue.empty()&&_isrunning){_waitnum++;ThreadSleep();_waitnum--;}//如果任务队列是空的,然后线程池又退出了,那么就没必要运行了if(_task_queue.empty() && !_isrunning){UnlockQueue();//std::cout<<name<<"quit..."<<std::endl;sleep(1);break;}//不论线程池有没有退出,走到这说明一定有任务 ->处理任务T t = _task_queue.front();_task_queue.pop();UnlockQueue();//解锁LOG(DEBUG, "%s 获得任务", name.c_str());t();LOG(DEBUG,"%s 处理任务中,结果是%s",name.c_str(), t.ResultToString().c_str());}}void Stop(){LockQueue();_isrunning = false;ThreadWakeupAll();UnlockQueue();        }void Wait(){for(auto &thread:_threads){thread.Join();LOG(INFO, "%s 线程退出...", thread.name().c_str());}}bool Enqueue(const T &t){bool ret = false;LockQueue();if(_isrunning){_task_queue.push(t);if(_waitnum>0){ThreadWakeup();}LOG(DEBUG, "任务入队列成功");ret = true;}UnlockQueue();return ret;}~ThreadPool()//析构{pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}
private:int _threadnum;//线程的数量std::vector<Thread> _threads;//用vector来存线程std::queue<T> _task_queue;//任务队列pthread_mutex_t _mutex;//锁pthread_cond_t _cond;//条件变量int _waitnum;bool _isrunning;//判断线程池是否在运行
};

thread.hpp

#include<iostream>
#include <string>
#include <unistd.h>
#include <functional>
#include <pthread.h>namespace ThreadModule
{using func_t = std::function<void(std::string)>;class Thread{public:void Excute(){_func(_threadname);}public:Thread(func_t func, std::string name="none-name"): _func(func), _threadname(name), _stop(true){}static void *threadroutine(void *args) // 类成员函数,形参是有this指针的!!{Thread *self = static_cast<Thread *>(args);self->Excute();return nullptr;}bool Start(){int n = pthread_create(&_tid, nullptr, threadroutine, this);if(!n){_stop = false;return true;}else{return false;}}void Detach(){if(!_stop){pthread_detach(_tid);}}void Join(){if(!_stop){pthread_join(_tid, nullptr);}}std::string name(){return _threadname;}void Stop(){_stop = true;}~Thread() {}private:pthread_t _tid;//线程tidstd::string _threadname;//线程名字func_t _func;//线程所要执行的函数bool _stop;//判断线程是否停止};
}

 

 main.cc

#include <iostream>	
#include <string>
#include <memory>
#include "LOG.hpp"
#include "threadpool.hpp"	
#include "Task.hpp"	
#include<ctime>int main()
{srand(time(nullptr) ^ getpid() ^ pthread_self());std::unique_ptr<ThreadPool<Task>> tp(new ThreadPool<Task>(5)); tp->InitThreadPool();tp->Start();int tasknum=3;while(tasknum){int a = rand() % 12 + 1;usleep(1000);int b = rand() % 4 + 1;Task t(a, b);LOG(INFO, "主线程推送任务: %s", t.DebugToString().c_str());tp->Enqueue(t);sleep(1);tasknum--;}tp->Stop();tp->Wait();return 0;
}


http://www.ppmy.cn/news/1475616.html

相关文章

uniapp vue3微信小程序如何获取dom元素

在网上很多人说可以通过下面两种形式获取到指定dom元素 // 定义ref <div ref"box"></div>//1通过this.$refs获取dom元素 this.$refs.box//2通过ref(null)获取dom元素 let box ref(null)第一种方式在vue2中是可以获取到的&#xff0c;但是在vue3 setup中…

LVS集群(二)

DR模式 LVS三种模式 nat地址转换 DR直接路由模式 tun隧道模式 DR模式的特点&#xff1a; 调度器在整个lvs集群中是最重要的&#xff0c;在nat模式中&#xff0c;负责接收请求&#xff0c;同时根据负载均衡算法转发流量&#xff0c;响应发送给客户端 DR模式&#xff1a;调度…

多头注意力机制详解:多维度的深度学习利器

引言 多头注意力机制是对基础注意力机制的一种扩展&#xff0c;通过引入多个注意力头&#xff0c;每个头独立计算注意力&#xff0c;然后将结果拼接在一起进行线性变换。本文将详细介绍多头注意力机制的原理、应用以及具体实现。 原理 多头注意力机制的核心思想是通过多个注…

ES6 Generator函数的异步应用 (八)

ES6 Generator 函数的异步应用主要通过与 Promise 配合使用来实现。这种模式被称为 “thunk” 模式&#xff0c;它允许你编写看起来是同步的异步代码。 特性&#xff1a; 暂停执行&#xff1a;当 Generator 函数遇到 yield 表达式时&#xff0c;它会暂停执行&#xff0c;等待 …

51单片机3(51单片机最小系统)

一、序言&#xff1a;由前面我们知道&#xff0c;51单片机要工作&#xff0c;光靠一个芯片是不够的&#xff0c;它必须搭配相应的外围电路&#xff0c;我们把能够使51单片机工作的最简单&#xff0c; 最基础的电路统称为51单片机最小系统。 二、最小系统构成&#xff1a;&…

阿里云产品流转

本文主要记述如何使用阿里云对数据进行流转&#xff0c;这里只是以topic流转&#xff08;再发布&#xff09;为例进行说明&#xff0c;可能还会有其他类型的流转&#xff0c;不同服务器的流转也可能会不一样&#xff0c;但应该大致相同。 1 创建设备 具体细节可看&#xff1a;…

centos环境启动/重启java服务脚本优化

centos环境启动/重启java服务脚本优化 引部分命令说明根据端口查询服务进程杀死进程函数脚本接收参数 脚本注意重启文档位置异常 引 在离线环境部署的多个java应用组成的系统&#xff0c;测试阶段需要较为频繁的发布&#xff0c;因资源限制&#xff0c;没有弄devops或CICD那套…

【QT】Qt事件

目录 前置知识 事件概念 常见的事件描述 进入和离开事件 代码示例&#xff1a; 鼠标事件 鼠标点击事件 鼠标释放事件 鼠标双击事件 鼠标滚轮动作 键盘事件 定时器事件 开启定时器事件 窗口相关事件 窗口移动触发事件 窗口大小改变时触发的事件 扩展 前置知识…

Vue3响应系统的作用与实现

副作用函数的执行会直接或间接影响其他函数的执行。一个副作用函数中读取了某个对象的属性&#xff0c;当该属性的值发生改变后&#xff0c;副作用函数自动重新执行&#xff0c;这个对象就是响应式数据。 1 响应式系统的实现 拦截对象的读取和设置操作。当读取某个属性值时&a…

澳门建筑插画:成都亚恒丰创教育科技有限公司

澳门建筑插画&#xff1a;绘就东方之珠的斑斓画卷 在浩瀚的中华大地上&#xff0c;澳门以其独特的地理位置和丰富的历史文化&#xff0c;如同一颗璀璨的明珠镶嵌在南国海疆。这座城市&#xff0c;不仅是东西方文化交融的典范&#xff0c;更是建筑艺术的宝库。当画笔轻触纸面&a…

STM32MP135裸机编程:唯一ID(UID)、设备标识号、设备版本

0 资料准备 1.STM32MP13xx参考手册1 唯一ID&#xff08;UID&#xff09;、设备标识号、设备版本 1.1 寄存器说明 &#xff08;1&#xff09;唯一ID 唯一ID可以用于生成USB序列号或者为其它应用所使用&#xff08;例如程序加密&#xff09;。 &#xff08;2&#xff09;设备…

conda install问题记录

最近想用代码处理sar数据&#xff0c;解放双手。 看重了isce这个处理平台&#xff0c;在安装包的时候遇到了一些问题。 这一步持续了非常久&#xff0c;然后我就果断ctrlc了 后面再次进行尝试&#xff0c;出现一大串报错&#xff0c;不知道是不是依赖项的问题 后面看到说mam…

前端预览图片的两种方式:转Base64预览或转本地blob的URL预览,并再重新转回去

&#x1f9d1;‍&#x1f4bb; 写在开头 点赞 收藏 学会&#x1f923;&#x1f923;&#x1f923; 预览图片 一般情况下&#xff0c;预览图片功能&#xff0c;是后端返回一个图片地址资源&#xff08;字符串&#xff09;给前端&#xff0c;如&#xff1a;ashuai.work/static…

搜维尔科技:scalefit人体工程学分析表明站立式工作站的高度很重要

搜维尔科技&#xff1a;scalefit人体工程学分析表明站立式工作站的高度很重要 搜维尔科技&#xff1a;scalefit人体工程学分析表明站立式工作站的高度很重要

红酒与未来科技:传统与创新的碰撞

在岁月的长河中&#xff0c;红酒以其深邃的色泽、丰富的口感和不同的文化魅力&#xff0c;成为人类文明中的一颗璀璨明珠。而未来科技&#xff0c;则以其迅猛的发展速度和无限的可能性&#xff0c;领着人类走向一个崭新的时代。当红酒与未来科技相遇&#xff0c;一场传统与创新…

【2024最新】C++扫描线算法介绍+实战例题

扫描线介绍&#xff1a;OI-Wiki 【简单】一维扫描线&#xff08;差分优化&#xff09; 网上一维扫描线很少有人讲&#xff0c;可能认为它太简单了吧&#xff0c;也可能认为这应该算在差分里&#xff08;事实上讲差分的文章里也几乎没有扫描线的影子&#xff09;。但我认为&am…

1.26、基于概率神经网络(PNN)的分类(matlab)

1、基于概率神经网络(PNN)的分类简介 PNN(Probabilistic Neural Network,概率神经网络)是一种基于概率论的神经网络模型,主要用于解决分类问题。PNN最早由马科夫斯基和马西金在1993年提出,是一种非常有效的分类算法。 PNN的原理可以简单概括为以下几个步骤: 数据输入层…

Tomcat的服务部署于优化

一、tomcat是一个开源的web应用服务器&#xff0c;nginx主要处理静态页面&#xff0c;那么静态请求&#xff08;连接数据库&#xff0c;动态页面&#xff09;并不是nginx的强项&#xff0c;动态的请求会交给Tomcat进行处理&#xff0c;tomcat是用java代码写的程序&#xff0c;运…

[leetcode]partition-list 分隔链表

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:ListNode* partition(ListNode* head, int x) {ListNode *smlDummy new ListNode(0), *bigDummy new ListNode(0);ListNode *sml smlDummy, *big bigDummy;while (head ! nullptr) {if (head->val &l…

【数学建模】——【线性规划】及其在资源优化中的应用

目录 线性规划问题的两类主要应用&#xff1a; 线性规划的数学模型的三要素&#xff1a; 线性规划的一般步骤&#xff1a; 例1&#xff1a; 人数选择 例2 &#xff1a;任务分配问题 例3: 饮食问题 线性规划模型 线性规划的模型一般可表示为 线性规划的模型标准型&…