【Linux】线程(第十六篇)
目录
线程
1.线程基本概述:
2.线程类型:
3.线程间的共享资源与非共享资源
4.线程原语
1.线程创建函数
2.获取当前线程id的函数
3.回收线程资源
4.将线程设置为分离态
5.结束线程
6.退出线程
线程
1.线程基本概述:
是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。ubuntu线程为LWP(轻量级进程)
线程id 为tid
lwp 为 线程编号
查看线程的命令
ps -eLf 查看系统中所有的线程
ps -Lf pid 查看指定进程里的线程
线程与进程的区别
线程与进程的差异:相比于进程而言,线程体积更小更轻量(进程是最小的分配资源的单位,线程是最小的调度单位)
进程创建时,内核对进程进行初始化并分配资源(内核)
线程寄存于进程中,与进程共享资源,线程隶属于进程的一部分
注意:线程既可以使用CPU,当时间片耗尽时产生中断,可以实现保存和恢复处理器现场,满足分时复用原则,为系统调度单位
2.线程类型:
用户级线程、内核级线程、混合型线程
用户级线程:默认系统不支持线程比如UBUNTU,需要安装第三方线程库,使用时因为所有的库内容都在用户层,直接访问即可,无需产生层级转换,切换频率低,运行效率高,速度快。 用户级线程即装即用,系统无需支持线程,对系统依赖较低,有较好的兼容性 用户级线程没有对应的内核对象,无法被系统内核识别,无论线程数量变为多少,也不会改变资源分配策略,无法得到更多的系统资源
内核级线程:系统内置线程原语,无需外部支持即可创建使用线程,线程创建后为每个线程创建内核对象,因为是系统函数,每个函数使用时都会产生系统调用,进行频繁的层级转换,相比于用户级线程,效率更低,执行成本高。 每个线程都有对应的内核对象,系统可识别,内核级线程变多,资源分配调整,该进程可能得到更多的资源,从而缩短整体任务的完成时间
混合型线程:该类线程采纳的用户型与内核型的优点,线程定义在用户层,便于使用,降低切换频率,提高执行效率,为线程创建内核对象,系统可识别,可以获取更多的系统资源
3.线程间的共享资源与非共享资源
共享资源:文件描述符表共享、堆空间共享、全局资源静态资源共享、信号行为共享(捕捉、默认、忽略)、pid(进程id) 非共享资源:线程栈(8M) 、信号屏蔽字非共享、 tid(线程id)、线程调度优先级、ERROR全局变量非共享
ubuntu系统中的全局变量errno 比如int fd = open("files")函数调用失败,将错误号设置到全局的errno变量中,perror(错误处理) 。线程有自己的处理方式,无需用perror 、errono
4.线程原语
POSIX Thread Library (NPTL)使Linux内核可以非常有效的运行使用POSIX线程标准写的程序。
1.线程创建函数
#include <pthread.h>
int pthread_create(
pthread_t *restrict tidp, //新创建的线程ID指向的内存地址。
const pthread_attr_t *restrict attr, //线程属性,默认为NULL
void *(*start_rtn)(void *), //新创建的线程从start_rtn函数的地址开始运行
void *restrict arg //默认为NULL。若上述函数需要参数,将参数放入结构中并将地址作为arg传入。
);
返回值 成功返回0,失败返回int 错误号,开发者可以通过错误号errono 获取对应得错误信息
const char* strerror(int errono); //该函数参数为错误号,返回字符串错误信息,大多数线程库函数都使用这种错误判断和处理方式
2.获取当前线程id的函数
#include <pthread.h>
pthread_t pthread_self(void);//成功返回当前线程得id
3.回收线程资源
int pthread_join(
pthread_t tid, //需要等待的线程,指定的线程必须位于当前的进程中,而且不得是分离线程
void **status //线程tid所执行的函数返回值(返回值地址需要保证有效),其中status可以为NULL
);
.pthread非linux系统的默认库, 需手动链接-线程库 -lpthread
.指定线程tid进行回收操作,可以回收线程资源以及线程得返回值并传出到status中 .阻塞函数,等待线程结束后进行回收 .如果不进行回收,不仅无法获取线程得返回值,还能产生僵尸线程
只有在pthread_join
函数返回时,该线程才会释放自己的资源。 或者是设置在分离属性的情况下,一个线程结束会立即释放它所占用的资源。
4.将线程设置为分离态
pthread_detach(pthread_t tid);//将一个线程退出状态置为分离态
线程有两种中退出状态,线程默认得退出状态为(回收态 JOIN),另一种为(分离态(DETACHED)) 如果一个线程被设置为分离态线程,那么这个线程结束后系统自动回收该线程资源(无需用户干预),用户无法获取该线程返回值 两种退出状态互斥,如果对已经处于回收阶段得线程设置分离,分离无效,对已经分离成功得线程进行join回收操作,回收操作失败
5.结束线程
pthread_cancel(pthread_t tid); //线程取消,某线程可以用该函数结束另外一个线程
示例:
线程里只有while(1); 调用pthread_cancel 取消线程.实现不了。
原理:pthread_cancel向线程发送事件,如果线程里while(1);则处理不了,线程不能退出。线程出现系统调用时会检测取消事件,否则无法处理 解决办法: pthread_testcancel(); 产生一次系统调用(空调用)。
cancel事件得处理依赖关系调用,如果线程中没有系统调用可能无法被取消结束,通过pthread_testcancel可以产生系统调用
6.退出线程
pthread_exit(void*); 线程退出函数,哪个线程调用哪个线程结束
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
void* mythread(void* lpvoid)
{
// pthread_detach(pthread_self());//将线程设为分离态
//printf("my thread is running,threadid is %x...\n",(unsigned int)pthread_self());
while(1)
{
pthread_testcancel();//系统调用(空调用)
}
return (void*)1;
}
int main()
{
int err;
void* revalue;
pthread_t tid;
err = pthread_create(&tid,NULL,mythread,NULL);//创建线程
if(err >0)
{
printf("pthread_create failed is %s\n",strerror(err));
exit(0);
}
//sleep(2);
pthread_cancel(tid); //向指定线程发送退出事件
pthread_join(tid,(void**)&revalue); //回收线程
printf("thread id is %x...,exit return value %ld\n",(unsigned int)tid,(long int)revalue);
while(1)sleep(1);
return 0;
}