【linux】系统编程-5-线程
前言
7. 线程
7.1 概念
进程:进程是资源管理的最小单位
线程:线程是程序执行的最小单位
因为进程开销大,才衍生出线程
- 进程切换上下文时, 需要重新映射虚拟地址空间、进出OS内核、寄存器切换,还会干扰处理器的缓存机制
一个进程至少需要一个线程作为它的指令执行体,进程管理着资源(比如cpu、内存、文件等等), 而将线程分配到某个cpu上执行
新的执行线程将拥有自己的栈,但与它的创建者共享全局变量、文件描述符、信号处理函数和当前目录状态
特点:
- 一个程序至少有一个进程,一个进程至少有一个线程
- 线程使用进程的资源,进程崩溃,线程也随之崩溃
- 线程切换上下文快,进程切换上下文慢
使用 pthread_create 创建线程
使用 int pthread_attr_destroy(pthread_attr_t *attr); 函数来销毁一个线程属性对象
使用 pthread_attr_init() 函数可以初始化线程对象的属性
使用 pthread_join() 等待线程结束
使用 pthread_detach() 来设置线程为分离状态
7.2 创建线程
7.2.1 pthread_create()
- 使用 pthread_create 创建线程
- 通过命令 man 了解更多
- 所需要的头文件:
#include <pthread.h>
- 函数原型:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
- thread:指向线程标识符的指针
- attr:设置线程属性
- start_routine:函数指针,线程入口
- arg:传给线程入口函数的参数
7.3 设置线程属性
- 线程属性结构体 pthread_attr_t:
typedef struct{
int etachstate; //线程的分离状态
int schedpolicy; //线程调度策略
structsched_param schedparam; //线程的调度参数
int inheritsched; //线程的继承性
int scope; //线程的作用域
size_t guardsize; //线程栈末尾的警戒缓冲区大小
int stackaddr_set; //线程的栈设置
void* stackaddr; //线程栈的位置
size_t stacksize; //线程栈的大小
}pthread_attr_t;
- 注意:
- 因为 pthread 并非 Linux 系统的默认库,而是 POSIX线程库。在Linux中将其作为一个库来使用, 因此编译时需要加上-lpthread(或-pthread)以显式指定链接该库
- 函数在执行错误时,并不把错误信息写到变量 error 中,而是作为返回值返回
- 线程属性不能直接设置,只能通过函数操作
- 线程属性包括:作用域(scope)、栈大小(stacksize)、栈地址(stackaddress)、优先级(priority)、 分离的状态(detachedstate)、调度策略和参数(scheduling policy and parameters)
- 线程的默认属性:非绑定、非分离、1M的堆栈大小、与父进程同样级别的优先级
- API:
API | 说明 |
---|---|
pthread_attr_init() | 初始化一个线程对象的属性 |
pthread_attr_destroy() | 销毁一个线程属性对象 |
pthread_attr_getaffinity_np() | 获取线程间的CPU亲缘性 |
pthread_attr_setaffinity_np() | 设置线程的CPU亲缘性 |
pthread_attr_getdetachstate() | 获取线程分离状态属性 |
pthread_attr_setdetachstate() | 修改线程分离状态属性 |
pthread_attr_getguardsize() | 获取线程的栈保护区大小 |
pthread_attr_setguardsize() | 设置线程的栈保护区大小 |
pthread_attr_getscope() | 获取线程的作用域 |
pthread_attr_setscope() | 设置线程的作用域 |
pthread_attr_getstack() | 获取线程的堆栈信息(栈地址和栈大小) |
pthread_attr_setstack() | 设置线程堆栈区 |
pthread_attr_getstacksize() | 获取线程堆栈大小 |
pthread_attr_setstacksize() | 设置线程堆栈大小 |
pthread_attr_getschedpolicy() | 获取线程的调度策略 |
pthread_attr_setschedpolicy() | 设置线程的调度策略 |
pthread_attr_setschedparam() | 获取线程的调度优先级 |
pthread_attr_getschedparam() | 设置线程的调度优先级 |
pthread_attr_getinheritsched() | 获取线程是否继承调度属性 |
pthread_attr_getinheritsched() | 设置线程是否继承调度属性 |
7.3.1 pthread_attr_init()
- 使用 pthread_attr_init 初始化线程对象属性
- 通过命令 man 了解更多
- 所需要的头文件:
#include <pthread.h>
- 函数原型:
int pthread_attr_init(pthread_attr_t *attr);
- attr:指向一个线程属性的指针
- 返回:
- 成功:返回 0
- 失败:返回 非 0
7.3.2 销毁一个线程属性对象
- 使用
int pthread_attr_destroy(pthread_attr_t *attr);
函数来销毁一个线程属性对象- attr:指向一个线程属性的指针
- 返回:
- 成功:返回 0
- 失败:返回 错误码
7.3.3 线程的分离状态
在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)
- 可结合的线程:能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的
- 分离的线程:不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放
线程的分离状态决定一个线程以什么样的方式来终止自己
默认状态下是 非分离状态
函数:
int pthread_join(pthread_t tid, void **rval_ptr);
- 等待某个线程的终止,获得该线程的终止状态,并收回所占的资源
- tid:线程标识符
- rval_ptr设置为NULL,则忽略返回状态
int pthread_detach(pthread_t tid);
- 将线程设置为分离状态
- 头文件:
#include <pthread.h>
- tid:线程标识符
- 返回:
- 成功:返回 0
- 失败:返回一个错误值:
- EINVAL:tid 对应的线程不是一个 非分离的线程
- ESRCH:找不到对应的线程
在非分离状态下:
- 原有线程等待创建的线程结束,只有当 pthread_join() 函数放回时,创建的线程才算真正终止
在分离状态下:
- 该线程没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源
如果在创建线程时就知道不需要了解线程的终止状态,则可以 pthread_attr_t 结构中的 detachstate 线程属性,让线程以分离状态启动
- 使用
pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
函数来设置线程分离状态- attr:指向一个线程属性的指针
- detachstate:
- PTHREAD_CREATE_DETACHED:分离线程
- PTHREAD _CREATE_JOINABLE:非分离线程
- 使用
获取某个线程的分离状态
- 使用
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
函数获取线程的分离状态 - attr:指向一个线程属性的指针
- detachstate:保存状态的值
- 返回:
- 成功:返回 0
- 失败:返回 错误码
- 使用
注意:
- 如果设置一个线程为分离线程,而这个线程运行又非常快,它很可能在 pthread_create 函数返回之前就终止了,它终止以后就可能将线程号和系统资源移交给其他的线程使用,这样调用 pthread_create 的线程就得到了错误的线程号。要避免这种情况可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用 pthread_cond_timewait 函数,让这个线程等待一会儿,留出足够的时间让函数 pthread_create 返回。设置一段等待时间,是在多线程编程里常用的方法。但是注意不要使用诸如 wait() 之类的函数,它们是使整个进程睡眠,并不能解决线程同步的问题。
7.3.4 线程的调度策略
POSIX 标准指定了三种调度策略:
- 普通线程(默认)SCHED_OTHER。采用时分调度策略,不需要实时机制。另外两种用于超级用户权限时运行。
- 实时线程SCHDE_FIFO。采用实时调度-先进先出方式策略。一旦占用cpu则一直运行,直到有更高优先级任务到达或自己放弃。
- 轮询调度SCHED_RR。采用实时调度-时间片轮转方式调度策略。当任务的时间片用完,系统将重新分配时间片,并置于就绪队列尾。放在队列尾保证了所有具有相同优先级的RR任务的调度公平。所以说SCHED_RR=SCHED_OTHER+SCHDE_FIFO。
与调度相关的API
- 参数说明:
- attr:指向一个线程属性的指针。
- inheritsched:线程是否继承调度属性,可选值分别为
- PTHREAD_INHERIT_SCHED:调度属性将继承于创建的线程,attr中设置的调度属性将被忽略。
- PTHREAD_EXPLICIT_SCHED:调度属性将被设置为attr中指定的属性值。
- policy:可选值为线程的三种调度策略
- SCHED_OTHER
- SCHED_FIFO
- SCHED_RR
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched); int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
- 参数说明:
7.3.5 线程优先级
- SCHED_OTHER调度时
- 静态优先级必须置为 0
- 处于静态优先级为 0 的线程按照动态优先级被调度
- 动态优先级值起始于 nice 值,且当前线程处于就绪态并被调度器无视时,其动态值++,以保证竞争CPU的公平性
- 线程优先级的设置(静态优先级)(SCHED_FIFO和SCHED_RR)
- 通过以下函数来获得线程可以设置的最高和最低优先级(不支持SCHED_OTHER)
int sched_get_priority_max(int policy);
int sched_get_priority_min(int policy);
- 通过以下两个函数来设置和获取优先级
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
- 线程优先级特点
- 新线程的优先级默认为 0
- 新线程不继承父线程调度优先级(PTHREAD_EXPLICIT_SCHED)
- 当线程的调度策略为SCHED_OTHER时,不允许修改线程优先级,仅当调度策略为实时(即SCHED_FIFO或SCHED_RR)时才有效, 并可以在运行时通过pthread_setschedparam()函数来改变,默认为0。
7.3.6 线程栈
- 线程栈:
- 用于存放函数形参、局部变量、线程切换现场寄存器等数据。
- 使用的是进程的地址空间,默认线程栈大小是 1M
- 设置和获取线程大小可以使用一下函数
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);
7.4 退出线程
- 线程退出使用
void pthread_exit(void *retval);
函数 - 注意:不能使用 exit() 函数退出,因为该函数是直接退出进程的,会把进程内所有函数都退出。
参考
* 野火
【linux】系统编程-5-线程的更多相关文章
- linux系统编程:线程原语
线程原语 线程概念 线程(thread),有时被称为轻量级进程(Lightweight Process,LWP).是程序运行流的最小单元.一个标准的线程由线程ID.当前指令指针(PC),寄存器集合和堆 ...
- Linux系统编程:线程控制
一.提出问题 问1.线程存在的意义是什么?什么时候适合使用多线程? 答1.在单进程环境中实现多任务,线程可访问其所在进程的资源,例如内存.描述符等.对于单进程,如果要完成多项任务,这些任务只能依次执行 ...
- linux系统编程:线程同步-相互排斥量(mutex)
线程同步-相互排斥量(mutex) 线程同步 多个线程同一时候訪问共享数据时可能会冲突,于是须要实现线程同步. 一个线程冲突的演示样例 #include <stdio.h> #includ ...
- linux系统编程:线程同步-信号量(semaphore)
线程同步-信号量(semaphore) 生产者与消费者问题再思考 在实际生活中,仅仅要有商品.消费者就能够消费,这没问题. 但生产者的生产并非无限的.比如,仓库是有限的,原材料是有限的,生产指标受消费 ...
- Linux系统编程——线程私有数据
在多线程程序中.常常要用全局变量来实现多个函数间的数据共享.因为数据空间是共享的,因此全局变量也为全部线程共同拥有. 測试代码例如以下: #include <stdio.h> #inclu ...
- Linux 系统编程 学习:09-线程:线程的创建、回收与取消
Linux 系统编程 学习:09-线程:线程的创建.回收与取消 背景 我们在此之前完成了 有关进程的学习.从这一讲开始我们学习线程. 完全的开发可以参考:<多线程编程指南> 在Linux ...
- Linux 系统编程 学习:10-线程:线程的属性
Linux 系统编程 学习:10-线程:线程的属性 背景 上一讲我们介绍了线程的创建,回收与销毁:简单地提到了线程属性.这一讲我们就来具体看看,线程的属性. 概述 #include <pthre ...
- Linux 系统编程 学习:11-线程:线程同步
Linux 系统编程 学习:11-线程:线程同步 背景 上一讲 我们介绍了线程的属性 有关设置.这一讲我们来看线程之间是如何同步的. 额外安装有关的man手册: sudo apt-get instal ...
- Linux系统编程温故知新系列 --- 01
1.大端法与小端法 大端法:按照从最高有效字节到最低有效字节的顺序存储,称为大端法 小端法:按照从最低有效字节到最高有效字节的顺序存储,称为小端法 网际协议使用大端字节序来传送TCP分节中的多字节整数 ...
- 读书笔记之Linux系统编程与深入理解Linux内核
前言 本人再看深入理解Linux内核的时候发现比较难懂,看了Linux系统编程一说后,觉得Linux系统编程还是简单易懂些,并且两本书都是讲Linux比较底层的东西,只不过侧重点不同,本文就以Linu ...
随机推荐
- 第7.3节 Python特色的面向对象设计:协议、多态及鸭子类型
Python是一种多态语言,其表现特征是:对象方法的调用方只管方法是否可调用,不管对象是什么类型,从而屏蔽不同类型对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化. 一. P ...
- PyQt(Python+Qt)学习随笔:QTableWidget项编辑方法editItem、openPersistentEditor
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 1.触发编辑项的editItem方法 QTableWidget提供了触发项编辑的方法,调用语法如下: ...
- 使用文件描述符作为Python内置函数open的file实参调用示例
一.关于文件描述符 open()函数的file参数,除了可以接受字符串路径外,还可以接受文件描述符(file descriptor),文件描述符是个整数,对应程序中已经打开的文件. 文件描述符是操作系 ...
- PyQt(Python+Qt)学习随笔:Qt Designer中部件的焦点策略focusPolicy设置
在Qt Designer中可以设置部件的焦点策略,部件的焦点策略属性取值范围由枚举类型Qt.FocusPolicy来定义,该枚举类型及其含义如下表所示: 注意:经老猿测试鼠标轮滚动获取焦点,只有在鼠标 ...
- PyQt(Python+Qt)学习随笔:Qt Designer中主窗口对象的animated属性
animated属性用于设置在操作可浮动部件和工具栏时是否设置动画. 当一个可浮动部件或工具栏被拖到主窗口上时,主窗口将调整其内容,以显示浮动部件或工具栏应该放置的位置.设置此属性后主窗口将使用平滑动 ...
- Dr.COM获取用户属性超时!请检查防火墙配置允许UDP 61440端口。怎么解决
最近校园网老是出问题,看到好多同学都遇到了下面的问题,我就来说一下我的解决方法.(目前我认识的有三个同学遇到了这样的情况,用这个方法都解决了,但不一定对每个人都有效) 首先登陆net.scut.edu ...
- centos7网卡bond配置--自己另一篇文章的补充
这篇文章是自己另一篇文章的第二种方法的一个完善的补充 https://www.cnblogs.com/zzf0305/p/9588585.html 1 备份网卡配置文件2 使用nmcli命令配置bon ...
- uni-app中使用sass
uni-app在创建时,工程目录下会有个uni.scss文件,我们可以直接在里面定制化scss变量. 全局scss中的坑: 1.如果要引用全局外部scss文件,可以考虑在uni.scss这个系统全局s ...
- html文本域textarea高度自增、自动换行
文本域自动换行.高度自增,采用以下方式: html: <textarea rows="1" class="answerTextArea" maxlengt ...
- Linux命令-1.远程登录
原网站:http://www.runoob.com/linux/linux-remote-login.html Linux一般作为服务器使用,而服务器一般放在机房,你不可能在机房操作你的Linux服务 ...