Linux多线程服务端编程 第四章

C++多线程系统编程精要
学习多线程编程面临的思维转变有两点:
1.当前线程可能随时会被切换出去,或者说被抢占;
2.多线程程序中实践的发生顺序不再有全局统一的先后关系。

多线程程序的正确性不能依赖于任何一个线程的执行速度,不能通过原地等待(sleep())来假定其他线程的事件已经发生,而必须通过适当的同步来让当前线程能看到其他线程的事件的结果。


11个最基本的Pthreads函数是:
2个:线程的创建和等待结束(join)。封装为muduo::Thread
4个:mutex的创建、销毁、等待、通知、广播。封装为muduo::MutexLock
5个:条件变量的创建、销毁、等待、通知、广播。封装为muduo::Condition

C/C++系统库的线程安全性
C++的标准库容器和std::string都不是线程安全的,只有std::allocator保证是线程安全的。一方面的原因是为了避免不必要的性能开销,另一方面的原因是单个成员函数的线程安全并不具备可组合性。
例如:
safe_vector<int> vec; //全局可见
if(!vec.empty()) //没有加锁保护
{
int x = vec[0]; //这两步在多线程下是不安全的
}

线程的创建与销毁的守则
线程的创建和销毁需要遵循几条简单的原则:
1.程序库不应该在未提前告知的情况下创建自己的“背景线程”;
2.尽量用相同的方式创建线程,例如muduo::Thread;
3.在进入main()函数之前不用改启动线程;
4.程序中线程的创建最好能在初始化阶段全部完成。

线程销毁的集中方式:
1.自然死亡。从线程主函数返回,线程正常退出。
2.非正常死亡。从线程主函数抛出异常或线程触发segfault信号等非操作;
3.***。在线程中调用pthread_exit()来立刻退出线程,
4.他杀。其他线程调用pthread_cancel()来强制终止某个线程。

多线程与IO
多个线程
同时操作同一个socket文件描述符需要考虑的情况如下:
1.如果一个线程正在阻塞地read某个socket,而另一个线程close了此socket。
2.如果一个线程正在阻塞地accept某个listening socket,而另一个线程close了此socket;
3.一个线程正准备read某个socket,而另一个线程close了此socket,第三个线程又恰好open了另一个文件描述符,而fd号码刚好和之前的socket相同。

RAII
我们可以用对象来包装资源,把资源管理与对象生命周期管理统一起来(RAII)。

多线程与fork()
fork()之后,子进程不能调用:
1.malloc()
2.任何可能分配或释放内存的函数,包括new、map::insert()、snprintf
3.任何Pthread函数
4.printf()系列函数
5.除了明确列出的“signal安全”函数之外的任何函数

多线程与signal
在多线程程序中,使用signal的第一原则是不要使用signal:
1.不要用signal作为IPC的手段;
2.也不要使用基于signal实现的定时函数;
3.不主动处理各种异常信号;
4.在没有别的替代方法的情况下,把异步信号转换为同步的文件描述符事件。

小结
1.一台机器上不应该同时运行几百个、几千个用户线程,这会大大增加内核scheduler的负担;
2.一个程序最好在一开始创建所需的线程,并一直反复使用;
3.每个线程应该有明确的职责美丽如IO线程、计算线程;
4.线程之间的交互应尽量简单;
5.要预先考虑清楚一个mutable shared对象将会暴露给哪些线程。
#Linux#
全部评论

相关推荐

点赞 16 评论
分享
牛客网
牛客企业服务