(1)线程(LWP) 可使用命令查看指定线程的LWP号: ps -Lf pid
1)light weigh process(轻量级进程),本质上仍然是进程
进程:独立的地址空间,拥有PCB,最小分配资源单位,内存分配资源以进程为标准。
线程:没有独立的地址空间(共享),拥有PCB,最小的执行单位,CPU分配时间轮片是以线程为标准。
2)线程和进程的联系和区别
1>线程也有PCB,创建线程使用的底层函数和进程一样,都是clone。
2>从内核里看进程和线程都是一样的,都有各自不同的PCB,但PCB中指向内存的三级页表是相同的(类似于指向相同内存的指针,指针不同,但是内存相同)。
三级映射:进程PCB--->页目录(4kb)-->页表---->物理页面---->内存单元
3>进程可以退变成线程。
4>线程可以看做寄存器和栈的集合
3)线程资源和优缺点
1)共享资源
文件描述符 信号处理方式 工作目录 用户id和组id 内存地址空间(除栈空间和errno变量)
2)独享资源
线程id 处理器现场和栈指针(内核栈)和独立的栈空间(用户栈 ) errno变量 信号屏蔽字 调度优先级
3)线程优缺点
优点:提高程序并发性 开销小(针对于进程) 数据通信共享数据方便(进程:IPC通信)
缺点:使用库函数,不稳定 调试编译困难,gdb不支持(出现在gdb之后) 对信号支持不好
(2)线程控制原语
1)获取线程id: pthread_t pthread_self(void); ---->对应进程getpid()
pthread_t pthread_self(void); 返回值:成功 0 失败 无
pthread_t:为linux下的无符号整数(%lu)
线程ID为进程内部,识别标志,两个进程之间线程id允许相同。
2)创建一个新线程 :pthread_create --->对应进程的fork()
int pthread_create(pthread_t *thtrad,const pthread_attr_t *attr,void*(*start_routinue)(void *),void *arg);
返回值 成功:0 失败:错误号(linux环境下线程的特点:失败均返回错误号,不能使用perror,而应该使用sterror函数)
参数 1:保存系统为分配的线程id
2:通常设置为NULL,表示使用线程的默认属性(可使用具体参数修改该参数)
3:函数指针,指向线程主函数(线程体)。函数运行结束,则线程结束。
4:主函数执行期间所使用的参数。
使用pthread_create循环创建多个线程,每个线程打印自己是第几个被创造的线程
1>实现和结果
直接将整形转化为指针类型,如果是32位的操作系统,直接转换。如果是64位的操作系统,则是小端转大端问题,前头补零,数据不变化。
2>代码修改:(换成取地址,符合我们正常的理解,结果有问题)
如果是取地址的话,则线程去i的时候可能其他的线程也来了,此时两个线程公用全局变量,使得两个i值混乱。可以直接利用两个线程之间不共享栈的特点,直接采用值传递,而不是址传递。
3)单个进程退出:pthread_exit函数
void pthread_exit(void* retval) 参数:retval 表示线程退出状态,通常传NULL
在多线程中 exit ,return ,pthread_exit的区别:
exit:进程中的所有线程退出,在线程中应该禁止使用exit.
return:返回到调用者那里,继续执行下一步程序。
pthread_exit:退出单个线程
结论:多线程环境中,应该尽量不用或者少用exit函数,取而代之用pthread_exit函数。pthread_exit或者return返回的指针所指向的内存必须是全局或者malloc分配的(不同线程不共享栈)
4)阻塞等待线程退出,获取线程退出状态 :pthread_join ---->对应进程中的waitpid()
int pthread_join(pthread_t thread,void **retval); 成功:0 失败:错误号
参数:线程id ,retavl:储存线程结束状态。
5)线程分离:pthread_detach(常用与网路和多线程服务器)
int pthread_detach(pthread_t thread) 成功:0 失败:错误号
线程分离:线程主动与主控线程断开联系。线程结束后,其退出状态不由其他线程获取,而是自己主动释放(不会产生僵尸进程)(也可以通过pthread_create 通过设置参数2实现线程分离)
使用了线程分离的线程不能够在使用pthread_join,这样调用返回EINVAL错误
6)杀死(取消)线程:pthread_cancel函数 --->进程的kill函数
int pthread_cancel(pthread_t thread); 成功:0 失败:错误号
注意:线程的取消和杀死并不是实时的,而是有一定的延时性,需要等待线程到底某个取消点或者检查点(通常是系统调用,可通过 man 7 pthread查看取消点列表,也可以通过pthread_testcancel()函数来自行设置一个取消点)
当我们对一个已经取消的线程使用pthread_join时,返回值是-1.
终止线程的方式:
1>线程主函数return 返回,不适用于主控线程。
2>一个线程调用pthread_cancel终止同一个进程中的另一个线程。
3>线程可以调用pthread_exit终止自己。