You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

141 lines
4.4KB

  1. /*
  2. * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
  3. *
  4. * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
  5. *
  6. * Use of this source code is governed by MIT license that can be found in the
  7. * LICENSE file in the root of the source tree. All contributing project authors
  8. * may be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #include <csignal>
  11. #include <iostream>
  12. #include <random>
  13. #include "Util/util.h"
  14. #include "Util/logger.h"
  15. #include "Util/ResourcePool.h"
  16. #include "Thread/threadgroup.h"
  17. #include <list>
  18. using namespace std;
  19. using namespace toolkit;
  20. //程序退出标志
  21. bool g_bExitFlag = false;
  22. class string_imp : public string{
  23. public:
  24. template<typename ...ArgTypes>
  25. string_imp(ArgTypes &&...args) : string(std::forward<ArgTypes>(args)...){
  26. DebugL << "创建string对象:" << this << " " << *this;
  27. };
  28. ~string_imp(){
  29. WarnL << "销毁string对象:" << this << " " << *this;
  30. }
  31. };
  32. //后台线程任务
  33. void onRun(ResourcePool<string_imp> &pool,int threadNum){
  34. std::random_device rd;
  35. while(!g_bExitFlag){
  36. //从循环池获取一个可用的对象
  37. auto obj_ptr = pool.obtain();
  38. if(obj_ptr->empty()){
  39. //这个对象是全新未使用的
  40. InfoL << "后台线程 " << threadNum << ":" << "obtain a emptry object!";
  41. }else{
  42. //这个对象是循环使用的
  43. InfoL << "后台线程 " << threadNum << ":" << *obj_ptr;
  44. }
  45. //标记该对象被本线程使用
  46. obj_ptr->assign(StrPrinter << "keeped by thread:" << threadNum );
  47. //随机休眠,打乱循环使用顺序
  48. usleep( 1000 * (rd()% 10));
  49. obj_ptr.reset();//手动释放,也可以注释这句代码。根据RAII的原理,该对象会被自动释放并重新进入循环列队
  50. usleep( 1000 * (rd()% 1000));
  51. }
  52. }
  53. int main() {
  54. //初始化日志
  55. Logger::Instance().add(std::make_shared<ConsoleChannel>());
  56. Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
  57. //大小为50的循环池
  58. ResourcePool<string_imp> pool;
  59. pool.setSize(50);
  60. //获取一个对象,该对象将被主线程持有,并且不会被后台线程获取并赋值
  61. auto reservedObj = pool.obtain();
  62. //在主线程赋值该对象
  63. reservedObj->assign("This is a reserved object , and will never be used!");
  64. thread_group group;
  65. //创建4个后台线程,该4个线程模拟循环池的使用场景,
  66. //理论上4个线程在同一时间最多同时总共占用4个对象
  67. WarnL << "主线程打印:" << "开始测试,主线程已经获取到的对象应该不会被后台线程获取到:" << *reservedObj;
  68. for(int i = 0 ;i < 4 ; ++i){
  69. group.create_thread([i,&pool](){
  70. onRun(pool,i);
  71. });
  72. }
  73. //等待3秒钟,此时循环池里面可用的对象基本上最少都被使用过一遍了
  74. sleep(3);
  75. //但是由于reservedObj早已被主线程持有,后台线程是获取不到该对象的
  76. //所以其值应该尚未被覆盖
  77. WarnL << "主线程打印: 该对象还在被主线程持有,其值应该保持不变:" << *reservedObj;
  78. //获取该对象的引用
  79. auto &objref = *reservedObj;
  80. //显式释放对象,让对象重新进入循环列队,这时该对象应该会被后台线程持有并赋值
  81. reservedObj.reset();
  82. WarnL << "主线程打印: 已经释放该对象,它应该会被后台线程获取到并被覆盖值";
  83. //再休眠3秒,让reservedObj被后台线程循环使用
  84. sleep(3);
  85. //这时,reservedObj还在循环池内,引用应该还是有效的,但是值应该被覆盖了
  86. WarnL << "主线程打印:对象已被后台线程赋值为:" << objref << endl;
  87. {
  88. WarnL << "主线程打印:开始测试主动放弃循环使用功能";
  89. List<decltype(pool)::ValuePtr> objlist;
  90. for (int i = 0; i < 8; ++i) {
  91. reservedObj = pool.obtain();
  92. string str = StrPrinter << i << " " << (i % 2 == 0 ? "此对象将脱离循环池管理" : "此对象将回到循环池");
  93. reservedObj->assign(str);
  94. reservedObj.quit(i % 2 == 0);
  95. objlist.emplace_back(reservedObj);
  96. }
  97. }
  98. sleep(3);
  99. //通知后台线程退出
  100. g_bExitFlag = true;
  101. //等待后台线程退出
  102. group.join_all();
  103. return 0;
  104. }