王柳 发表于 2024-9-29 02:19:27

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


[*] 单例模式的线程安全

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

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

[*]原因2:

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


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

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


[*] while()防止伪唤醒

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

static const int THREAD_POOL_NUM = 10;

// 单例模式
class ThreadPool
{
public:
    static ThreadPool *GetInstance(int num = THREAD_POOL_NUM)
    {
      static pthread_mutex_t sMtx = PTHREAD_MUTEX_INITIALIZER;
      if (_tp == nullptr)
      {
            pthread_mutex_lock(&sMtx);
            if (_tp == nullptr) // 双重判断,以防线程安全问题
            {
                _tp = new ThreadPool(num);
                _tp->Init();
            }
            pthread_mutex_unlock(&sMtx);
      }

      return _tp;
    }

    // static使该成员函数没有this指针,因为线程执行的函数只能有一个void*参数
    static void *ThreadRoutine(void *args)
    {
      ThreadPool *tp = (ThreadPool *)args;

      while(true)
      {
            Task task;
            tp->Lock();
            while(tp->TaskQueueIsEmpty()) // while防止伪唤醒
            {
                tp->ThreadWait();
            }
            tp->Pop(task);
            tp->Unlock(); // 注意,不要在临界资源区内处理任务哦~
            task.ProcessOn();
      }
    }

    bool Init()
    {
      for (int i = 0; i < _num; i++)
      {
            pthread_t tid;
            if (pthread_create(&tid, nullptr, ThreadRoutine, this) != 0)
            {
                LOG(FATAL, "Create ThreadPool Error");
                return false;
            }
      }
      LOG(INFO, "Create ThreadPool Success");
      
      return true;
    }

    void Push(const Task& task) // in
    {
      Lock();
      _taskQueue.push(task); // 任务队列为临界资源,操作要加锁
      Unlock();

      ThreadWakeUp();
    }

    void Pop(Task& task) // out
    {
      task = _taskQueue.front();
      _taskQueue.pop();
    }

    void ThreadWait()
    {
      pthread_cond_wait(&_cond, &_mtx);
    }

    void ThreadWakeUp()
    {
      pthread_cond_signal(&_cond);
    }

    bool TaskQueueIsEmpty()
    {
      return !_taskQueue.size();
    }

    void Lock()
    {
      pthread_mutex_lock(&_mtx);
    }

    void Unlock()
    {
      pthread_mutex_unlock(&_mtx);
    }

    bool IsStop()
    {
      return _stop;
    }

    ~ThreadPool()
    {
      pthread_mutex_destroy(&_mtx);
      pthread_cond_destroy(&_cond);
    }
private:
    ThreadPool(int num = THREAD_POOL_NUM)
      : _num(num), _stop(false)
    {
      pthread_mutex_init(&_mtx, nullptr);
      pthread_cond_init(&_cond, nullptr);
    }

    ThreadPool(const ThreadPool &) = delete;
private:
    int _num;
    bool _stop;
    std::queue<Task> _taskQueue;
    pthread_mutex_t _mtx;
    pthread_cond_t _cond;
    static ThreadPool *_tp;
};

ThreadPool* ThreadPool::_tp = nullptr;

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: [项目][WebServer][ThreadPool]详细讲解