当前位置:网站首页>17.13 补充知识、线程池浅谈、数量谈、总结
17.13 补充知识、线程池浅谈、数量谈、总结
2022-06-26 17:46:00 【zzyzxb】
一:补充一些知识点
<1>虚假唤醒
class MA
{
public:
int i = 0;
std::unique_lock<std::mutex> rtn_unique_gurad()
{
std::unique_lock <std::mutex> tmpgurad(my_mutex_1);
return tmpgurad; //从函数返回一个局部的unique_lock对象是可以的,三章十四届讲过移动构造函数
//返回这种局部对象会导致系统生成临时unique_lock对象,并调用unique_lock的移动构造函数
}
//把收到的消息(玩家命令)放入到一个队列的线程
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; ++i)
{
cout << "inMsgRecvQueue()执行,插入一个元素: " << i << endl;
std::unique_lock<std::mutex> sbguard_1 = rtn_unique_gurad();
msgRecvQueue.push_back(i); //假设这个数字i就是我们收到的命令,直接弄到消息队列中
//假如outMsgRecvQueue()正在处理一个事务,需要一段时间,而不是正卡在wait()那里等待唤醒;
//那么此时这个notify_one()这个调用也许就没效果。
my_cond.notify_one(); //我们尝试把wait()线程唤醒,执行完这行,那么outMsgRecvQueue()里边的wait()就会被唤醒
}
cout << "i = " << i << endl;
}
//把数据从消息队列中取出的线程
void outMsgRecvQueue()
{
int command = 0;
while (true)
{
//wait()用来等待一个东西
//如果第二个参数lambda表达式返回值是true,那wait()直接返回;
//如果第二个参数lambda表达式返回值是false,那么wait()将解锁互斥量,并堵塞到本行
//那堵塞到什么时候为止呢?堵塞到其他某个线程调用notify_one()成员函数为止;
//如果wait()没有第二个参数:my_cond.wait(sbguard1); 那么就跟第二个参数lambda表达式返回false效果一样,堵塞本行
//wait()将解锁互斥量,并阻塞到本行,阻塞到其他某个线程调用欧冠notify_one()成员函数为止;
//当其他线程用notify_one()将本wait()(原来是睡着/阻塞)的状态唤醒后,wait就开始恢复干活了,恢复后wait干什么活?
//a> wait()不断的尝试重新获取互斥量锁,如果获取不到,那么流程就卡在wait()这这里等着获取,如果获取到了锁(等于加了锁),那么wait()就继续执行b;
//b>
//b.1> 如果wait()有第二个参数(lambda),就判断这个lambda表达式,如果lambda表达式为false,那wait()又对互斥量解锁,然后又休眠这里等待再次被notify_one唤醒;
//b.2> 如果lambda表达式为true, 则wait返回,流程走下来(此时互斥锁被锁着);
//b.3> 如果wait()没有第二个参数,则wait()返回,流程走下来。
std::unique_lock<std::mutex> sbguard_1(my_mutex_1);
my_cond.wait(sbguard_1, [this] { //一个lambda就是一个可调用对象(函数)
if (!msgRecvQueue.empty())
return true;
return false;
});
//流程只要能走到这里来,这个互斥锁一定是锁着的,同时msgRecvQueue至少是有一条数据的
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
sbguard_1.unlock(); //因为unique_lock的灵活性,所以我们可以随时的unlock解锁,以免锁住太长时间。
cout << "outMsgRecvQueue()执行,取出一个元素 " << command << " " << std::this_thread::get_id() << endl;
} //end while
cout << "end" << endl;
}
private:
list<int> msgRecvQueue; //容器(消息队列),专门用于代表玩家发送的命令
mutex my_mutex_1; //创建了一个互斥量 (一把锁头)
std::condition_variable my_cond; //生成一个条件变量对象
};
int main()
{
MA myobj;
std::thread myOutMsgObj(&MA::outMsgRecvQueue, &myobj); //第二个参数是引用,才能保证线程里用的是同一个对象
std::thread myInMsgObj(&MA::inMsgRecvQueue, &myobj);
myOutMsgObj.join();
myInMsgObj.join();
cout << "main主函数执行结束" << endl; //最后执行这句,整个进程退出
return 0;
}
虚假唤醒:wait中要有第二个参数(lambda)并且这个lambda中要正确判断要处理的公共数据是否存在;
wait()、notify_one()、notify_all()。
<2>atomic
class MA
{
public:
MA()
{
atm = 0;
}
public:
void inMsgRecv()
{
for (int i = 0; i < 10000000; ++i)
{
//atm += 1;
atm = atm + 1; //读atm是个原子操作,但是整个这一行代码并不是个原子操作
//auto atm2 = atm; //这种定义时初始化操作不允许,显示“尝试引用已删除的函数”编译器内部肯定把拷贝构造函数给干掉了用 =delete,因为编译器不好操作
//atomic<int> atm2 = atm; //也不允许
//atomic<int> atm2;
//atm2 = atm //尝试引用已删除的函数,拷贝赋值运算符也不让用
//load():以原子方式读atomic对象的值
atomic<int> atm2(atm.load()); //读
auto atm3(atm.load());
//store()以原子方式写入内容
atm2.store(12);
atm2 = 12;
}
}
void outMsgRecv()
{
int command = 0;
while (true)
{
cout << "atm = " << atm << endl;
} //end while
cout << "end" << endl;
}
private:
atomic<int> atm;
};
int main()
{
MA myobj;
std::thread myOutMsgObj(&MA::outMsgRecv, &myobj); //第二个参数是引用,才能保证线程里用的是同一个对象
std::thread myInMsgObj(&MA::inMsgRecv, &myobj);
std::thread myInMsgObj2(&MA::inMsgRecv, &myobj);
myOutMsgObj.join();
myInMsgObj.join();
myInMsgObj2.join();
cout << "main主函数执行结束" << endl; //最后执行这句,整个进程退出
return 0;
}
二:浅谈线程池
<1>场景设想
服务器程序 -> 客户端,每来一个客户端,就创建一个新线程为该客户提供服务。
(1)网络游戏,2万玩家不可能给每个玩家创建个新线程,此程序写法在这种场景下不通;
(2)程序稳定性问题:编写的代码中,偶尔创建一个线程这种代码,这种写法,就让人感到不安;
线程池:把一堆线程弄到一起,统一管理。这种统一管理调试,循环利用线程方式,就叫线程池。
<2>实现方式:
在程序启动时,一次性的创建好一定数量的线程。10,8,100-200,更让人放心,觉得程序代码更稳定。
三:线程创建数量谈
<1>线程开的数量极限问题,2000个线程基本就是极限,再创建线程就崩溃。
<2>线程创建数量建议
(1)采用某些技术开发程序;api接口提供商建议你创建线程数量 = CPU数量、CPU * 2、CPU * 2 + 2,遵照专业建议和指示来;专业意见确保程序高效执行;
(2)创建多线程完成业务;一个线程等于一条通路;100要堵塞充值,我们这里开110个线程,那是很合适的;
(3)1800个线程,建议线程数量尽量不要超过500个,能控制在200以内。
四:c++11多线程总结
边栏推荐
- Here comes the hero League full skin Downloader
- 14 MySQL tutorial insert insert data
- Microservice architecture practice: user login and account switching design, order query design of the mall
- Leetcode daily [2022 - 02 - 16]
- Viewing the task arrangement ability of monorepo tool from turborepo
- Vue--vuerouter cache routing component
- Preparing for the Blue Bridge Cup and ccf-csp
- How does Guosen Securities open an account? Is it safe to open a stock account through the link
- Play with Linux and easily install and configure MySQL
- How sparksql returns a specific day of the week by date -dayofweek function
猜你喜欢
Don't believe it, 98% of programmers are like this
SIGIR 2022 | 港大等提出超图对比学习在推荐系统中的应用
Niuke network: Design LRU cache structure design LFU cache structure
Rich professional product lines, and Jiangling Ford Lingrui · Jijing version is listed
[suggested collection] 11 online communities suitable for programmers
vutils.make_grid()与黑白图像有关的一个小体会
清华&商汤&上海AI&CUHK提出Siamese Image Modeling,兼具linear probing和密集预测性能!
pycharm的plt.show()如何保持不关闭
丰富专业化产品线, 江铃福特领睿·极境版上市
9、智慧交通项目(2)
随机推荐
vue--vuerouter缓存路由组件
Strength and appearance Coexist -- an exclusive interview with Liu Yu, a member of Apache pulsar PMC
Niuke network: Design LRU cache structure design LFU cache structure
Synchronized description of concurrency
LeetCode——226. Flip binary tree (BFS)
背包问题求方案数
【代码随想录-动态规划】T583、两个字符串的删除操作
Problems encountered this week
Ndroid development from introduction to mastery Chapter 2: view and ViewGroup
陈强:阿里千亿级大规模数字商业知识图谱助力业务增长
Jouer avec Linux et installer et configurer MySQL facilement
Programmer's essential toolkit, please collect!
小程序设置按钮分享功能
宝藏又小众的CTA动画素材素材网站分享
Tsinghua & Shangtang & Shanghai AI & CUHK proposed Siamese image modeling, which has both linear probing and intensive prediction performance!
Quantitative contract system development analysis case - detailed explanation of contract quantitative system development scheme
Platform management background and merchant menu resource management: Design of platform management background data service
量化合约系统开发分析案例丨合约量化系统开发方案详解
Prometeus 2.34.0 新特性
接水面试题