[项目][WebServer][ThreadPool]详细讲解

王柳  金牌会员 | 2024-9-29 02:19:27 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 890|帖子 890|积分 2670


  • 单例模式的线程安全

    • 必要双重判空指针,低沉锁冲突的概率,进步性能
    • 原因1:

      • 当第一次实例化单例时,可能有多个线程同时到来,而且svr指针为空
      • 这时他们就会去竞争锁,但只有一个线程会最快拿到锁,而且乐成实例化出单例对象
      • 但此时如果不加双重判空指针,那些也进了第一层if判断的,仍然会去实例化出对象

    • 原因2:

      • 为了线程安全,肯定要加锁,加锁之后再去判空
      • 但每次调用GetInstance()都必要去获得锁,释放锁,服从低下
      • 此时再加一层外层if判空,这样就会避免后续调用GetInstance()时没必要的锁竞争


  • static void *ThreadRoutine(void *args)为什么要设置为static方法?

    • pthread_create传递给线程的方法只能是返回值为void*,参数为void*的函数
    • static将函数方法声明为静态方法,此时该方法没有隐含的this指针,就可以在类内把这个方法传递给线程调用了
      1. int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
      2.                           void *(*start_routine) (void *), void *arg);
      复制代码

  • while()防止伪唤醒

    • 可能条件变量唤醒线程时,有多个线程同时被唤醒,但是只有一个最快的线程PopTask()可以拿到任务,此时其他线程就会出错
    • while()可以在被唤醒的情况下,再次判断任务队列是否有任务
    • 这样可以包管,在某个线程醒来的时间,肯定是占据互斥锁的

  1. static const int THREAD_POOL_NUM = 10;
  2. // 单例模式
  3. class ThreadPool
  4. {
  5. public:
  6.     static ThreadPool *GetInstance(int num = THREAD_POOL_NUM)
  7.     {
  8.         static pthread_mutex_t sMtx = PTHREAD_MUTEX_INITIALIZER;
  9.         if (_tp == nullptr)
  10.         {
  11.             pthread_mutex_lock(&sMtx);
  12.             if (_tp == nullptr) // 双重判断,以防线程安全问题
  13.             {
  14.                 _tp = new ThreadPool(num);
  15.                 _tp->Init();
  16.             }
  17.             pthread_mutex_unlock(&sMtx);
  18.         }
  19.         return _tp;
  20.     }
  21.     // static使该成员函数没有this指针,因为线程执行的函数只能有一个void*参数
  22.     static void *ThreadRoutine(void *args)
  23.     {
  24.         ThreadPool *tp = (ThreadPool *)args;
  25.         while(true)
  26.         {
  27.             Task task;
  28.             tp->Lock();
  29.             while(tp->TaskQueueIsEmpty()) // while防止伪唤醒
  30.             {
  31.                 tp->ThreadWait();
  32.             }
  33.             tp->Pop(task);
  34.             tp->Unlock(); // 注意,不要在临界资源区内处理任务哦~
  35.             task.ProcessOn();
  36.         }
  37.     }
  38.     bool Init()
  39.     {
  40.         for (int i = 0; i < _num; i++)
  41.         {
  42.             pthread_t tid;
  43.             if (pthread_create(&tid, nullptr, ThreadRoutine, this) != 0)
  44.             {
  45.                 LOG(FATAL, "Create ThreadPool Error");
  46.                 return false;
  47.             }
  48.         }
  49.         LOG(INFO, "Create ThreadPool Success");
  50.         
  51.         return true;
  52.     }
  53.     void Push(const Task& task) // in
  54.     {
  55.         Lock();
  56.         _taskQueue.push(task); // 任务队列为临界资源,操作要加锁
  57.         Unlock();
  58.         ThreadWakeUp();
  59.     }
  60.     void Pop(Task& task) // out
  61.     {
  62.         task = _taskQueue.front();
  63.         _taskQueue.pop();
  64.     }
  65.     void ThreadWait()
  66.     {
  67.         pthread_cond_wait(&_cond, &_mtx);
  68.     }
  69.     void ThreadWakeUp()
  70.     {
  71.         pthread_cond_signal(&_cond);
  72.     }
  73.     bool TaskQueueIsEmpty()
  74.     {
  75.         return !_taskQueue.size();
  76.     }
  77.     void Lock()
  78.     {
  79.         pthread_mutex_lock(&_mtx);
  80.     }
  81.     void Unlock()
  82.     {
  83.         pthread_mutex_unlock(&_mtx);
  84.     }
  85.     bool IsStop()
  86.     {
  87.         return _stop;
  88.     }
  89.     ~ThreadPool()
  90.     {
  91.         pthread_mutex_destroy(&_mtx);
  92.         pthread_cond_destroy(&_cond);
  93.     }
  94. private:
  95.     ThreadPool(int num = THREAD_POOL_NUM)
  96.         : _num(num), _stop(false)
  97.     {
  98.         pthread_mutex_init(&_mtx, nullptr);
  99.         pthread_cond_init(&_cond, nullptr);
  100.     }
  101.     ThreadPool(const ThreadPool &) = delete;
  102. private:
  103.     int _num;
  104.     bool _stop;
  105.     std::queue<Task> _taskQueue;
  106.     pthread_mutex_t _mtx;
  107.     pthread_cond_t _cond;
  108.     static ThreadPool *_tp;
  109. };
  110. ThreadPool* ThreadPool::_tp = nullptr;
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王柳

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表