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

DieSnowK 2024-10-03 10:33:00 阅读 66

单例模式的线程安全

需要双重判空指针,降低锁冲突的概率,提高性能原因1:

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

为了线程安全,必然要加锁,加锁之后再去判空但每次调用<code>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;



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。