【Linux】线程(下)

发布时间:2026/8/25 10:27:31
【Linux】线程(下) 同步在保证数据安全的前提下让线程能够按照某种特定的顺序访问临界资源从而有效避免饥饿问题。条件变量条件变量是一种线程同步机制用于使线程在条件不满足时阻塞等待并在条件满足时由其他线程唤醒通常与互斥锁配合使用。cond:要初始化的条件变量 attr:NULLpthread_cond_wait让线程等待的时候会自动释放锁。唤醒等待int pthread_cond_broadcast(pthread_cond_t* cond);int pthread_cond_signal(pthread_cond_t* cond); 唤醒在cond等待队列中等待的一个线程通常是第一个。为什么pthread_cond_wait 需要互斥量?A:如果只有一个线程条件不满足会一直等下去所以必须要有一个线程通过某些操作改变共享变量使原先不满足的条件变满足并通知等待在条件变量上的线程。因为“条件的变化一定伴随着共享数据的变化”而共享数据如果不加锁就一定会出乱子。使用等待条件 pthread_mutex_lock(mutex); while (条件为假 { pthread_cond_wait(cond, mutex); } 修改条件 pthread_mutex_unlock(mutex);给条件发送信号 pthread_mutex_lock(mutex); 设置条件为真 pthread_cond_signal(cond); pthread_mutex_unlock(mutex);判断也是访问临界资源所以判断必须在加锁以后。线程池单例线程池#pragmaonce#includeiostream#includevector#includestring#includequeue#includepthread.h#includeunistd.hstructThreadInfo{pthread_t tid;std::string name;};staticconstintdefaultnum5;templateclassTclassThreadPool{public:voidLock(){pthread_mutex_lock(_mutex);}voidUnlock(){pthread_mutex_unlock(_mutex);}voidWakeup(){pthread_cond_signal(_cond);}voidThreadSleep(){pthread_cond_wait(_cond,_mutex);}boolIsQueueEmpty(){return_tasks.empty();}std::stringGetThreadName(pthread_t tid){for(constautoti:_threads){if(ti.tidtid)returnti.name;}returnNone;}staticvoid*HandlerTask(void*args){ThreadPoolT*tpstatic_castThreadPoolT*(args);std::string nametp-GetThreadName(pthread_self());while(true){tp-Lock();while(tp-IsQueueEmpty()){tp-ThreadSleep();}T ttp-Pop();tp-Unlock();t();// 放在解锁后多个线程可以同时处理数据。std::coutname run, result: t.GetResult()std::endl;}}voidStart(){intnum_threads.size();for(inti0;inum;i){_threads[i].namethread-std::to_string(i1);pthread_create((_threads[i].tid),nullptr,HandlerTask,this);}}TPop(){T t_tasks.front();_tasks.pop();returnt;}voidPush(constTt){Lock();_tasks.push(t);Wakeup();Unlock();}staticThreadPoolT*GetInstance(){if(_tpnullptr){pthread_mutex_lock(_lock);if(_tpnullptr){std::coutlog:singleton create done first!std::endl;_tpnewThreadPoolT();}pthread_mutex_unlock(_lock);}return_tp;}private:ThreadPool(intnumdefaultnum):_threads(num){pthread_mutex_init(_mutex,nullptr);pthread_cond_init(_cond,nullptr);}~ThreadPool(){pthread_mutex_destroy(_mutex);pthread_cond_destroy(_cond);}//ThreadPool(constThreadPoolT)delete;constThreadPoolToperator(constThreadPoolT)delete;//private:std::vectorThreadInfo_threads;std::queueT_tasks;pthread_mutex_t _mutex;pthread_cond_t _cond;staticThreadPoolT*_tp;staticpthread_mutex_t _lock;};//templateclassTThreadPoolT*ThreadPoolT::_tpnullptr;templateclassTpthread_mutex_t ThreadPoolT::_lockPTHREAD_MUTEX_INITALIZER;//单例模式这个类只能有一个对象外部不能随便 new提供一个全局访问入口。饿汉方式实现templatetypenameTclassSingleton{staticT data;public:staticT*GetInstance(){returndata;}};懒汉方式实现templatetypenameTclassSingleton{staticT*inst;public:staticT*GetInstance(){if(instNULL){instnewT();}returninst;}};核心思想“延时加载”从而优化服务器的启动速度。存在线程不安全的问题。第一次调用GetInstance时若两个线程同时调用可能会创建出两份T对象实例。修改如下//线程安全templateclassTclassSingleton{volatilestaticT*inst;staticstd::mutex lock;public:staticT*GetInstance(){if(instNULL){lock.lock();if(instNULL){instnewT();}lock.unlock();}returninst;}};STL中的容器是否是线程安全的?不是.STL 的设计初衷是将性能挖掘到极致, 而一旦涉及到加锁保证线程安全, 会对性能造成巨大的影响.而且对于不同的容器, 加锁方式的不同, 性能可能也不同(例如hash表的锁表和锁桶).因此 STL 默认不是线程安全. 如果需要在多线程环境下使用, 往往需要调用者自行保证线程安全.智能指针是否是线程安全的?unique_ptr 通常用于局部作用域下的独占资源管理因为所有权唯一使用场景比 shared_ptr 简单如果它不被多个线程共享访问通常不需要额外考虑线程同步。对于 shared_ptr, 多个对象需要共用一个引用计数变量, 所以会存在线程安全问题. 但是标准库实现的时候考虑到了这个问题, 基于原子操作(CAS)的方式保证 shared_ptr 能够高效, 原子的操作引用计数.