• Linux如何设计一个线程池


    在设计线程池之前,我们可以对线程进行简单的封装这样子在线程池中就可以少一点调用接口,就像搭积木一样,一层一层的搭上去

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. // 上下文
    8. namespace ThreadNs
    9. {
    10. const int num = 1024;
    11. typedef std::function<void *(void *)> func_t;
    12. class Thread
    13. {
    14. private:
    15. // 在类内创建线程,想让线程执行对应的方法,需要将方法设置为static
    16. static void *start_routine(void *argv) // 类内成员,有缺省参数!this指针
    17. {
    18. // 静态方法不能调用成员方法和成员变量
    19. // 将成员设置成为静态的不推荐,友元也可以
    20. Thread *_this = static_cast(argv);
    21. return _this->calback();
    22. }
    23. public:
    24. Thread(const Thread &t)
    25. : _func(t._func), _args(t._args), _name(t._name)
    26. {
    27. }
    28. Thread()
    29. {
    30. // _name = "thread-";
    31. // _name += std::to_string(number);
    32. char namebuffer[num];
    33. snprintf(namebuffer, sizeof namebuffer, "thread - %d", Threadnum++);
    34. _name = namebuffer;
    35. }
    36. void start(func_t func, void *args = nullptr)
    37. {
    38. _func = func;
    39. _args = args;
    40. int n = pthread_create(&_tid, nullptr, start_routine, this);
    41. assert(n == 0);
    42. (void)n; // 有些编译器会报warning
    43. }
    44. void *calback() { return _func(_args);}
    45. std::string threadname()
    46. {
    47. return _name;
    48. }
    49. void join()
    50. {
    51. int n = pthread_join(_tid, nullptr);
    52. assert(n == 0);
    53. (void)n;
    54. }
    55. ~Thread()
    56. {
    57. // do nothing
    58. }
    59. private:
    60. std::string _name;
    61. pthread_t _tid;
    62. func_t _func;
    63. void *_args;
    64. static int Threadnum;
    65. };
    66. int Thread::Threadnum = 1;
    67. } // namespace ThreadNs

    这里的命名方式都是使用前_代表类内成员,我们将构造函数的参数设计的简单一点,方便后面实施,然后用_args代表要喂给线程的参数,_func代表回调函数。给每个线程设计一个名字使用_name

    线程池里面肯定要有线程,不过在此之前我们可以写一个Task的类方便后面测试,我这里写一个示例

    1. #pragma once
    2. #include
    3. #include
    4. class Task
    5. {
    6. public:
    7. using func_t = std::function<int(int,int, char)>;
    8. // typedef std::function func_t;
    9. Task()
    10. {}
    11. Task(int x, int y,char op, func_t func):_x(x),_y(y), _op(op),_callback(func)
    12. {}
    13. std::string operator()()
    14. {
    15. int result = _callback(_x,_y, _op);
    16. char buffer[1024];
    17. snprintf(buffer, sizeof buffer, "%d %c %d = %d", _x, _op, _y, result);
    18. return buffer;
    19. }
    20. std::string toTaskstring()
    21. {
    22. char buffer[1024];
    23. snprintf(buffer, sizeof buffer, "%d %c %d = ?", _x, _op, _y);
    24. return buffer;
    25. }
    26. private:
    27. int _x;
    28. int _y;
    29. char _op;
    30. func_t _callback;
    31. };
    32. const std::string oper = "+-*/%";
    33. int mymath(int x, int y, char op)
    34. {
    35. int result = 0;
    36. switch (op)
    37. {
    38. case '+':
    39. result = x + y;
    40. break;
    41. case '-':
    42. result = x - y;
    43. break;
    44. case '*':
    45. result = x * y;
    46. break;
    47. case '/':
    48. {
    49. if (y == 0)
    50. {
    51. std::cerr << "div zero error !" << std::endl;
    52. result = -1;
    53. }
    54. else
    55. result = x / y;
    56. }
    57. break;
    58. case '%':
    59. {
    60. if (y == 0)
    61. {
    62. std::cerr << "mod zero error !" << std::endl;
    63. result = -1;
    64. }
    65. else
    66. result = x % y;
    67. }
    68. break;
    69. default:
    70. break;
    71. }
    72. return result;
    73. }

    这是一个简单的算术任务类。

    接下来负责写线程池,线程池中肯定要有一系列线程,还有一个队列用于拿任务,还要有一个互斥锁和条件变量。当你完成了积木的底层以后上层就很容易了

    1. #pragma once
    2. #include "Mutex.hpp"
    3. #include "Thread.hpp"
    4. #include "Task.hpp"
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. using namespace ThreadNs;
    11. const int gnum = 5;
    12. template <class T>
    13. class ThreadPool;
    14. template <class T>
    15. class ThreadData
    16. {
    17. public:
    18. ThreadPool *_tp;
    19. std::string _name;
    20. public:
    21. ThreadData(ThreadPool *tp, const std::string &name) : _tp(tp), _name(name) {}
    22. };
    23. template <class T>
    24. class ThreadPool
    25. {
    26. private:
    27. static void *handlerTask(void *args)
    28. {
    29. ThreadData *td = (ThreadData *)args;
    30. // ThreadPool* tp = static_cast*> (args);
    31. while (1)
    32. {
    33. // sleep(1);
    34. // std::cout << "thread " << pthread_self() << " run ..." << std::endl;
    35. // td->_tp->lockQueue();
    36. T t;
    37. {
    38. LockGuard lockgurad(td->_tp->mutex());
    39. while (td->_tp->isEmptyQueue())
    40. {
    41. /* code */
    42. td->_tp->threadwait();
    43. }
    44. t = td->_tp->Pop();
    45. }
    46. // td->_tp->unlockQueue();
    47. std::cout << td->_name << "处理完了任务:" << t.toTaskstring() << t() << std::endl;
    48. }
    49. delete td;
    50. return nullptr;
    51. }
    52. public:
    53. void lockQueue() { pthread_mutex_lock(&_mutex); }
    54. void unlockQueue() { pthread_mutex_unlock(&_mutex); }
    55. bool isEmptyQueue() { return _task_queue.empty(); }
    56. void threadwait() { pthread_cond_wait(&_cond, &_mutex); }
    57. pthread_mutex_t *mutex() { return &_mutex; }
    58. T Pop()
    59. {
    60. T t = _task_queue.front();
    61. _task_queue.pop();
    62. return t;
    63. }
    64. ThreadPool(const int &num = gnum) : _num(num)
    65. {
    66. pthread_mutex_init(&_mutex, nullptr);
    67. pthread_cond_init(&_cond, nullptr);
    68. for (int i = 0; i < _num; i++)
    69. {
    70. _threads.push_back(new Thread());
    71. }
    72. }
    73. ThreadPool(const ThreadPool &) = delete;
    74. ThreadPool operator=(const ThreadPool &) = delete;
    75. public:
    76. void run()
    77. {
    78. for (const auto &t : _threads)
    79. {
    80. ThreadData *td = new ThreadData(this, t->threadname());
    81. t->start(handlerTask, td);
    82. std::cout << t->threadname() << "start ..." << std::endl;
    83. }
    84. }
    85. void push(const T &in)
    86. {
    87. // pthread_mutex_lock(&_mutex);
    88. LockGuard lockgurad(&_mutex);
    89. _task_queue.push(in);
    90. pthread_cond_signal(&_cond);
    91. // pthread_mutex_unlock(&_mutex);
    92. }
    93. ~ThreadPool()
    94. {
    95. pthread_mutex_destroy(&_mutex);
    96. pthread_cond_destroy(&_cond);
    97. for (const auto &t : _threads)
    98. delete t;
    99. }
    100. // 最好加static
    101. static ThreadPool *getInstance()
    102. {
    103. // LockGuard(&_mutex);
    104. if (nullptr == tp)
    105. {
    106. _singlock.lock();
    107. if (nullptr == tp)
    108. {
    109. tp = new ThreadPool();
    110. }
    111. _singlock.unlock();
    112. }
    113. return tp;
    114. }
    115. private:
    116. int _num;
    117. std::vector _threads;
    118. std::queue _task_queue;
    119. pthread_mutex_t _mutex;
    120. pthread_cond_t _cond;
    121. static ThreadPool *tp;
    122. static std::mutex _singlock;
    123. };
    124. template <class T>
    125. ThreadPool *ThreadPool::tp = nullptr;
    126. template <class T>
    127. std::mutex ThreadPool::_singlock;

  • 相关阅读:
    【KBQA-2】 Learning To Retrieve Prompts for In-Context Learning
    信奥一本通1167:再求f(x,n)//递归求解
    计算机毕业设计Python+django网上求职招聘系统(源码+系统+mysql数据库+Lw文档)
    Unity SpriteAtlas实战使用
    antd Checkbox 如何套多层
    SpringCloudAlibaba Ribbon Nacos 负载均衡的操作案例
    a16z公布AI产品流量排名,ChatGPT占据榜首
    Unity --- 虚拟轴的使用
    神经网络训练过程可视化,深度神经网络训练方法
    TS第四讲 ------ 函数
  • 原文地址:https://blog.csdn.net/2301_77312705/article/details/136466663