-
单例模式的线程安全
- 需要双重判空指针,降低锁冲突的概率,提高性能
- 原因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;