深圳建设网站公司排名,合肥外贸网站建设,推动房地产发展新模式,权威的大连网站建设线程属性设置 专栏内容#xff1a; 参天引擎内核架构 本专栏一起来聊聊参天引擎内核架构#xff0c;以及如何实现多机的数据库节点的多读多写#xff0c;与传统主备#xff0c;MPP的区别#xff0c;技术难点的分析#xff0c;数据元数据同步#xff0c;多主节点的情况…线程属性设置 专栏内容 参天引擎内核架构 本专栏一起来聊聊参天引擎内核架构以及如何实现多机的数据库节点的多读多写与传统主备MPP的区别技术难点的分析数据元数据同步多主节点的情况下对故障容灾的支持。 手写数据库toadb 本专栏主要介绍如何从零开发开发的步骤以及开发过程中的涉及的原理遇到的问题等让大家能跟上并且可以一起开发让每个需要的人成为参与者。 本专栏会定期更新对应的代码也会定期更新每个阶段的代码会打上tag方便阶段学习。 开源贡献 toadb开源库 个人主页我的主页 管理社区开源数据库 座右铭天行健君子以自强不息地势坤君子以厚德载物. 文章目录 线程属性设置前言概述线程属性栈属性栈地址栈大小栈保护区 调度属性继承属性调度策略属性优先级属性调度资源范围属性CPU亲和性属性 分离属性信号属性默认属性总结结尾 前言
现代的CPU都是多core处理器而且在intel处理器中每个core又可以多个processor形成了多任务并行处理的硬件架构在服务器端的处理器上架构又有一些不同传统的采用SMP也就是对称的多任务处理架构每个任务都可以对等的访问所有内存外设等而如今在ARM系列CPU上多采用NUMA架构它将CPU核分了几个组给每个组的CPU core分配了对应的内存和外设CPU访问对应的内存和外设时速度最优跨组访问时性能会降底一些。
随着硬件技术的持续发展它们对一般应用的性能优化能力越来越强同时对于服务器软件的开发提出更高要求要想达到极高的并发和性能就需要充分利用当前硬件架构的特点对它们进行压榨。那么我们的应用至少也是要采用多任务架构不管是多线程还是多进程的多任务架构才可以充分利用硬件的资源达到高效的处理能力。
当然多任务框架的采用不仅仅是多线程的执行需要对多任务下带来的问题进行处理如任务执行返回值获取任务间数据的传递任务执行次序的协调当然也不是任务越多处理越快要避免线程过多导致操作系统夯住也要防止任务空转过快导致CPU使用率飙高。
本专栏主要介绍使用多线程与多进程模型如何搭建多任务的应用框架同时对多任务下的数据通信数据同步任务控制以及CPU core与任务绑定等相关知识的分享让大家在实际开发中轻松构建自已的多任务程序。
概述
前一篇博客介绍了创建线程的步骤和调用的接口但是传递的参数都采用了默认值其实线程有很多属性值可以进行设置这样让多线程的应用运行更加的协调充分利用硬件资源。
本文就来分享一下线程的属性以及设置方法和接口最后会分享一段示例代码看一下设置效果。
特点说明一下这里分享的linux thread 库是Native Posix Thread Library(NPTL)也就是符合posix的接口为什么要强调这个呢因为linux 下的线程库有好几种各家实现都有一些差异也会存在一些问题而posix的这一套NTPL已经被大家广泛接受而大量使用所以我们也以这套库为基础来介绍编译时需要加-lptrhead或libpthread库引用。
线程属性
线程属性有很多这里分类列举一下。
属性名接口描述栈属性pthread_attr_getstack, pthread_attr_setstack设置栈地址和栈大小栈地址pthread_attr_getstackaddr, pthread_attr_setstackaddr设置栈地址栈大小pthread_attr_getstacksize, pthread_attr_setstacksize设置栈大小堆栈保护区pthread_attr_getguardsize, pthread_attr_setguardsize设置堆栈保护区大小分离状态pthread_attr_getdetachstate, pthread_attr_setdetachstate设置线程的可连接或分离调度继承属性pthread_attr_getinheritsched, pthread_attr_setinheritsched是否继承调度属性的设置调度优先级属性pthread_attr_getschedparam, pthread_attr_setschedparam调度优先级参数的设置调度策略属性pthread_attr_getschedpolicy, pthread_attr_setschedpolicy调度策略属性的设置调度资源的范围pthread_attr_getscope, pthread_attr_setscope设置调度资源的范围CPU 亲和性pthread_attr_getaffinity_nppthread_attr_setaffinity_np设置线程运行时绑定的CPU core信号掩码pthread_attr_getsigmask_np, pthread_attr_setsigmask_np信号掩码设置默认属性pthread_getattr_default_np, pthread_setattr_default_np设置为线程默认属性获取属性pthread_getattr_np获取线程实际属性
主要分为四大类
堆栈相关属性设置栈大小和起始地址还可以设置保护区给越界留有缓冲区调度相关属性CPU的绑定调度策略等分离状态对线程退出时资源的回收方式的设置信号掩码设置对线程级别的信号中断响应设置
栈属性
属性名接口描述栈属性pthread_attr_getstack, pthread_attr_setstack设置栈地址和栈大小栈地址pthread_attr_getstackaddr, pthread_attr_setstackaddr设置栈地址栈大小pthread_attr_getstacksize, pthread_attr_setstacksize设置栈大小堆栈保护区pthread_attr_getguardsize, pthread_attr_setguardsize设置堆栈保护区大小
主要有四组接口其中栈属性设置包括了对栈地址和栈大小的设置所以这里只介绍下面三组接口。
栈地址
int pthread_attr_setstack(pthread_attr_t *attr,void *stackaddr, size_t stacksize);
int pthread_attr_getstack(pthread_attr_t *attr,void **stackaddr, size_t *stacksize);int pthread_attr_getstackaddr(const pthread_attr_t *restrict attr,void **restrict stackaddr);
int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr); 设置线程栈的起始地址我们知道栈的地址是从起始地址开始从大到小的增长也就是向下连续的分配空间如果该地址超出了分配的栈区域的最高地址就会发生栈溢出。
不建议平常使用单独设置栈地址的功能 pthread_attr_setstackaddr由于无法提供指定增长方向或栈范围的方法; 而pthread_attr_setstack中指定了起始地址和stacksize参数指定的栈的范围可以分配连续的向下的区域。
栈大小
int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,size_t *restrict stacksize);
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);常用的是对栈大小的设置根据程序本身的特点如并发线程多少递归调用深度分配大的结构体数据等情况决定是否需要调整默认栈大小。
栈保护区
int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,size_t *restrict guardsize);
int pthread_attr_setguardsize(pthread_attr_t *attr,size_t guardsize); 出于以下两个原因为应用程序提供了 guardsize 属性 溢出保护可能会导致系统资源浪费。如果应用程序创建大量线程并且已知这些线程永远不会溢出其栈则可以关闭溢出保护区。通过关闭溢出保护区可以节省系统资源。 线程在栈上分配大型数据结构时可能需要较大的溢出保护区来检测栈溢出。
guardsize 参数提供了对栈指针溢出的保护。如果创建线程的栈时使用了保护功能则实现会在栈的溢出端分配额外内存。此额外内存的作用与缓冲区一样可以防止栈指针的栈溢出。如果应用程序溢出到此缓冲区中这个错误可能会导致 SIGSEGV 信号被发送给该线程。
如果 guardsize 为零则不会为线程提供溢出保护区。如果 guardsize 大于零则会为每个使用 attr 创建的线程提供大小至少为 guardsize 字节的溢出保护区。缺省情况下线程具有实现定义的非零溢出保护区。
允许合乎惯例的实现将 guardsize 的值向上舍入为可配置的系统变量 PAGESIZE 的倍数。
调度属性
属性名接口描述调度继承属性pthread_attr_getinheritsched, pthread_attr_setinheritsched是否继承调度属性的设置调度优先级属性pthread_attr_getschedparam, pthread_attr_setschedparam调度优先级参数的设置调度策略属性pthread_attr_getschedpolicy, pthread_attr_setschedpolicy调度策略属性的设置调度资源的范围pthread_attr_getscope, pthread_attr_setscope设置调度资源的范围CPU 亲和性pthread_attr_getaffinity_nppthread_attr_setaffinity_np设置线程运行时绑定的CPU core
线程调度属性主要有以下几种
继承属性调度参数属性调度策略属性CPU亲和性属性
继承属性
int pthread_attr_setinheritsched(pthread_attr_t *attr,int inheritsched);
int pthread_attr_getinheritsched(pthread_attr_t *attr,int *inheritsched);inherit 值为 PTHREAD_INHERIT_SCHED 表示新建的线程将继承创建者线程中定义的调度策略, 将忽略在 pthread_create() 调用中定义的所有调度属性。如果使用缺省值 PTHREAD_EXPLICIT_SCHED 则将使用 pthread_create() 调用中的属性。
调度策略属性
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(pthread_attr_t *attr, int *policy);这里的策略支持三种取值
当policy 取值为以下
SCHED_FIFO 先来先服务SCHED_RR 时间片轮转SCHED_OTHER 普通策略
前两种是realtime实时系统的调度策略一般不会使用它们两个支持优先级的设置范围是1-99
第三种是用户线程默认的策略类型在内核中的命名是SCHED_NORMAL, 不支持优先级设置必须为0 当然在SCHED_OTHER策略下的各用户线程之间可以通过调整nice值进行优先级调整它的范围为-20 - 19之间越小优先级越高。
优先级属性
int pthread_attr_setschedparam(pthread_attr_t *attr,const struct sched_param *param);
int pthread_attr_getschedparam(pthread_attr_t *attr,struct sched_param *param);调度参数在结构sched_param中定义仅支持优先级参数设定。
优先级参数仅在支持的调度策略下设置才有效在SCHED_OTHER, SCHED_IDLE, SCHED_BATCH这三种策略下优先级必须设置为0 在SCHED_FIFO, SCHED_RR这两种实时调度策略下优先级范围为1-99数字越大优先级越高
新创建的线程以此优先级运行, 简单示例代码如下
pthread_attr_t tattr;
int newprio;
sched_param param;/* set the priority; others are unchanged */
param.sched_priority 10;/* set the new scheduling param */
ret pthread_attr_setschedparam (tattr, param);调度资源范围属性
int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope);
int pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope);contentionscope的取值如下
PTHREAD_SCOPE_SYSTEM 线程在抢占资源与它竞争的线程是系统中的所有线程PTHREAD_SCOPE_PROCESS 线程在抢占资源时与它竞争的线程是本进程创建的线程优先级依赖与策略和优先级设定
CPU亲和性属性
int pthread_attr_setaffinity_np(pthread_attr_t *attr,size_t cpusetsize, const cpu_set_t *cpuset);
int pthread_attr_getaffinity_np(pthread_attr_t *attr, size_t cpusetsize, cpu_set_t *cpuset);参数说明
cpusetsize, 是第三个参数的size, 也就是sizeof(cpu_set_t);cpuset, 指定CPU core的掩码使用CPU_ZERO(set);和 CPU_SET(numCpu, set); 两个宏来设定numCpu指定绑定的core或thread编号是整型数字
参看机制的CPU 数量和core数量
[senllanghatch example_03]$ lscpu | egrep -i core.*:|socket
Thread(s) per core: 2
Core(s) per socket: 8
Socket(s): 1这里有一个CPU包含8个core每个core可以有两个线程那就是可以有16个掩码值设置时编号从0-15
有时CPU会采用NUMA架构那么相关线程需要设置到同一个Node的CPU编号下。
分离属性
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);detachstate的取值如下
PTHREAD_CREATE_DETACHED, 创建分离状态的线程此时不用关注线程退出时的资源回收PTHREAD_CREATE_JOINABLE, 创建可连接状态的线程线程退出时需要使用pthread_join对线程资源回收默认参数就是可连接状态的线程。
如果线程以PTHREAD_CREATE_JOINABLE创建后没有时机调用pthread_join时还可以调用pthread_detach 函数将指定线程置为分离状态这样系统会自动回收线程资源。
如果线程以PTHREAD_CREATE_JOINABLE创建后没有调用pthread_join会造成一定的内存泄漏这里一定要注意。
信号属性
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include pthread.hint pthread_attr_setsigmask_np(pthread_attr_t *attr,const sigset_t *sigmask);
int pthread_attr_getsigmask_np(const pthread_attr_t *attr,sigset_t *sigmask);设置线程级别的信号掩码也就是那些信号会被阻塞。 sigset_t 类型的操作需要使用一组信号掩码操作函数
int sigemptyset (sigset_t *set) 清空信号掩码变量int sigfillset (sigset_t *set) 填充所有信号掩码int sigaddset (sigset_t *set, int signum) 将某个信号添加到掩码中int sigdelset (sigset_t *set, int signum) 将某个信号从掩码中移除int sigismember (const sigset_t *set, int signum) 检测某个信号是否在掩码中
默认属性
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include pthread.hint pthread_getattr_default_np(pthread_attr_t *attr);
int pthread_setattr_default_np(pthread_attr_t *attr);int pthread_getattr_np(pthread_t thread, pthread_attr_t *attr);前两个函数是将线程属性设置为默认值也就是创建线程时将线程属性设置为NULL这两者是等价的。
第三个函数是获取指定线程的属性可以在线程运行过程中获取线程属性。
总结
本文主要分享了线程属性相关的接口以及部分属性的含义如何正确使用在应用编程时大多数情况下都会采用多线程并发的架构线程属性的正确使用能够帮助我们有提高CPU的利用效率同时在使用过程中避够资源泄漏也非常关键。
在gitCode上分享了工程hatchCode会不断增加多线程并发的案例代码请大家关注保留。
结尾 非常感谢大家的支持在浏览的同时别忘了留下您宝贵的评论如果觉得值得鼓励请点赞收藏我会更加努力 作者邮箱studysenllang.onaliyun.com 如有错误或者疏漏欢迎指出互相学习。