pthread_self 函数用于返回当前线程的标致符,类型为pthread_t
注意pthread_t:
无法打印输出,不知道确切类型,因此日志中无法用它表示当前线程无法比较大小或计算其hash值无法定义一个非法的pthread_t值来表示不可能存在的线程id只在进程中有意义,与操作系统的任务调度之间无法建立有效管理pthread_equal 对比两个线程标志符是否相等
Linux系统上建议gettid(2)系统调用的返回值来作为线程的id,原因如下
类型是pid_t,是一个小整数, 便于在日志中输出
它直接表示任务调度id,在/proc文件系统中可以轻易找到对应项
其他系统工具也容易定位到具体某一个线程,top(1)
任何时刻都是全局唯一的,分配新的pid是递增轮回办法
0是非法的,系统第一个进程init的pid是1;
线程的创建原则:
程序库不应该在为提前告知的情况下创建自己的“背景线程”尽量用相同的方式创建线程进入main函数之前不应该启动线程程序中线程的创建最好在初始化阶段全部完成线程的销毁方式
自然死亡。从线程的主函数返回,线程正常退出
非正常死亡,抛出异常或触发致命信号
自杀。 自己调用pthread_exit()退出
他杀。其他线程调用pthread_cancle()
注意,线程正常退出的方式只有一个,自然死亡,任何从外部强行终止线程的做法和想法都是错误的
exit(3)函数在C++中的作用除了终止线程,还会析构全局对象和以及构造完成的函数静态对象。这有存在死锁的可能
linux的文件描述符是小整数,程序刚启动时候,0是标准输入,1是标准输出,2是标准错误。因此新打开的文件描述符是3
POSIX标准要求每次打开文件的时候必须是当前最小可以文件描述符符号,因此这种方式会造成串话
比如:
第一个线程read某个socket,第二个线程几乎同时close此socket,第三个线程又打开了另一个文件描述符,与之前的相同,则会导致第一个线程会读不到属于他的数据fd = 8收到了比较耗时的请,开始处理这个请求,并记住将响应结果给fd = 8,.但是在处理过程中fd = 8 断开连接,于是在处理完成之后,返回响应已经物是人非了解决这个问题的办法
单线程程序,使用某种全局表d多线程程序:RAII,用Socket对象包装文件描述符,只要socket还活着,就不会有其他的Socket对象有相同的文件描述符fork()之后,子进程会继承父进程的几乎所有的状态,但也有少数例外
子进程会继承地址空间和文件描述符,因此用于管理动态内存和文件描述符的RAII class 都能正常工作,但是子进程不能继承:
父进程的内存锁父进程的文件锁父进程的某些定时器其他由此得出结论,RAII技法与fork冲突
多线程C++编写原则
线程时宝贵的,一个程序可以使用几个或几十个线程,但一台机器不应该同时运行几百个,几千个线程,会增加内核的负担线程的创建和销毁是有代价的,最好一开始就创建所有线程反复使用,如果必须那么做,最好是一分钟一次每个线程都应该有明确的职责,例如IO线程或计算线程线程之间的交互应该尽量简单,理想情况下只用消息传递,如果必须使用锁,最好避免同一个线程拥有两把锁考虑清楚一个mutable shared 对象会暴露给哪些线程,每个线程是读还是写,是否并发