这篇文章记述了关于多线程的知识点。
pthread_join
同步线程的三种方式是pthread_join,互斥锁和条件变量。
调用pthread_join将阻塞自己,直到要等待的线程运行结束,调用线程可以获取被调线程的返回值。
线程分为可以join和不可以join,该属性在创建线程时被指定。
joinable线程可在创建后,用pthread_detach()显式地分离。但分离后不可以再合并。该操作不可逆。
为了确保移植性,在创建线程时,最好显式指定其join或detach属性。似乎不是所有POSIX实现都是用joinable作默认。
pthread_detach
创建一个线程默认的状态是joinable, 如果一个线程结束运行但没有被join,则它的状态类似于进程中的Zombie Process,即还有一部分资源没有被回收(退出状态码),所以创建线程者应该调用pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源(类似于wait,waitpid)
但是调用pthread_join(pthread_id)后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此,比如在Web服务器中当主线程为每个新来的链接创建一个子线程进行处理的时候,主线程并不希望因为调用pthread_join而阻塞(因为还要继续处理之后到来的链接),这时可以在子线程中加入代码
pthread_detach(pthread_self())
或者父线程调用
pthread_detach(thread_id)(非阻塞,可立即返回)
这将该子线程的状态设置为detached,则该线程运行结束后会自动释放所有资源。
0327虚假唤醒spurious wakeup
今天参加了小方的多线程直播课程,印象里比较深刻的是他讲述了基础的重要性例如虚假唤醒的原语等,还讲述了他的flamingo客户端与服务器端代码,下面这幅图为什么810行使用while而不是使用if的原因是为了防止虚假唤醒:如果wait因为虚假唤醒而跳出等待,结果还有一个while等着它呢!

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| template<typename T> void threadpool<T>::run(){ while(!m_stop){ m_queuestat.wait(); std::lock_guard<std::mutex> lock(m_queuelocker); if(m_workqueue.empty()){ continue; } T* request = m_workqueue.front(); m_workqueue.pop_front(); if(!request){ continue; } request->process(); } }
|
单例模式
定义一个单例类:
- 私有化它的构造函数,以防止外界创建单例类的对象;
- 使用类的私有静态指针变量指向类的唯一实例;
- 使用一个公有的静态方法获取该实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class Log { public: static Log *get_instance() { static Log instance; return &instance; } ------------ void WebServer::log_write() { if (0 == m_close_log) { if (1 == m_log_write) Log::get_instance()->init("./ServerLog", m_close_log, 2000, 800000, 800); else Log::get_instance()->init("./ServerLog", m_close_log, 2000, 800000, 0); } } #define LOG_DEBUG(format, ...) if(0 == m_close_log) {Log::get_instance()->write_log(0, format, ##__VA_ARGS__); Log::get_instance()->flush();} #define LOG_INFO(format, ...) if(0 == m_close_log) {Log::get_instance()->write_log(1, format, ##__VA_ARGS__); Log::get_instance()->flush();} #define LOG_WARN(format, ...) if(0 == m_close_log) {Log::get_instance()->write_log(2, format, ##__VA_ARGS__); Log::get_instance()->flush();} #define LOG_ERROR(format, ...) if(0 == m_close_log) {Log::get_instance()->write_log(3, format, ##__VA_ARGS__); Log::get_instance()->flush();}
|