【linux 多线程并发】线程属性设置与查看,绑定CPU,线程分离与可连接,避够多线程下的内存泄漏

线程属性设置

专栏内容

  • 参天引擎内核架构
    本专栏一起来聊聊参天引擎内核架构,以及如何实现多机的数据库节点的多读多写,与传统主备,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_np,pthread_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_np,pthread_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数量

[senllang@hatch 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.h>int 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.h>int 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,会不断增加多线程并发的案例代码,请大家关注保留。

结尾

非常感谢大家的支持,在浏览的同时别忘了留下您宝贵的评论,如果觉得值得鼓励,请点赞,收藏,我会更加努力!

作者邮箱:study@senllang.onaliyun.com
如有错误或者疏漏欢迎指出,互相学习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/589162.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode1275. Find Winner on a Tic Tac Toe Game

文章目录 一、题目二、题解 一、题目 Tic-tac-toe is played by two players A and B on a 3 x 3 grid. The rules of Tic-Tac-Toe are: Players take turns placing characters into empty squares ’ . The first player A always places ‘X’ characters, while the seco…

Keras实现Transformer

# 导入所需的库 import numpy as np from keras.models import Model from keras.layers import Input, Dense, Embedding, MultiHeadAttention from keras.optimizers import Adam# 定义模型参数 vocab_size 10000 # 词汇表大小 embedding_dim 256 # 嵌入维度 num_heads …

营销系统升级:运荔枝无代码集成电商API功能

无代码开发&#xff1a;运荔枝连接电商与CRM 随着电子商务的持续扩张&#xff0c;企业亟需无缝集成电商平台与客户关系管理&#xff08;CRM&#xff09;系统&#xff0c;以提高运营效率。运荔枝通过其无代码开发平台&#xff0c;为企业提供了简化的API连接服务。商家可以在不具…

Prometheus 监控进程

prometheus 进程的监控 1. process exporter功能 2. 监控目标对主机进程的监控&#xff0c;chronyd sshd 等服务进程已经已定义脚本运行程序的运行状态监控。 process-compose的安装 监控所有进程 mkdir /data/process_exporter -p cd /data/process_exporter创建配置文件 …

Linux期末复习笔记

期末复习笔记 引言目录操作用户和组用户组 文件及文件权限文件文件目录及分类Linux文件目录文件类型文件权限 磁盘管理磁盘命名规则使用命令行工具管理磁盘分区和文件系统linux中的数据备份策略软件包安装检查维护文件系统 进程管理进程分类ps查看与top查看的区别&#xff1a; …

为什么ChatGPT选择了SSE,而不是WebSocket?

我在探索ChatGPT的使用过程中&#xff0c;发现了一个有趣的现象&#xff1a;ChatGPT在实现流式返回的时候&#xff0c;选择了SSE&#xff08;Server-Sent Events&#xff09;&#xff0c;而非WebSocket。 那么问题来了&#xff1a;为什么ChatGPT选择了SSE&#xff0c;而不是We…

力扣25题: K 个一组翻转链表

【题目链接】力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台&#xff0c;解题代码如下&#xff1a; class Solution {public ListNode reverseKGroup(ListNode head, int k) {ListNode curNode head;ListNode groupHead, groupTail head, lastGrou…

UART通信协议:串行通信的精华

UART通信协议&#xff1a;串行通信的精华 UART&#xff08;Universal Asynchronous Receiver/Transmitter&#xff09;通信协议是一种广泛应用于串行通信的标准&#xff0c;它在电子设备和嵌入式系统中扮演着至关重要的角色。本文将深入介绍UART通信协议的基本原理、工作方式、…

一个可以用于生产环境得PHP上传函数

上传表单 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>文件上传</title> </head> <body><h1>选择要上传的文件</h1><!-- 定义一个包含文件输入字段的表单 --…

[每周一更]-(第46期):Linux下配置Java所需环境及Java架构选型

Linux下配置Java所需环境及Java架构选型 一、配置基础环境 1.配置tomcat 环境变量 wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.8/src/apache-tomcat-10.1.8-src.tar.gz tar -zxvf apache-tomcat-10.1.8-src.tar.gz 在/etc/profile 末尾追加export CATALINA_HOME…

异常控制流ECF

大家好&#xff0c;我叫徐锦桐&#xff0c;个人博客地址为www.xujintong.com&#xff0c;github地址为https://github.com/xjintong。平时记录一下学习计算机过程中获取的知识&#xff0c;还有日常折腾的经验&#xff0c;欢迎大家访问。 一、异常控制流&#xff08;ECF) 现代系…

[BUG]Datax写入数据到psql报不能序列化特殊字符

1.问题描述 Datax从mongodb写入数据到psql报错如下 org.postgresql.util.PSQLException: ERROR: invalid bytesequence for encoding "UTF8": 0x002.原因分析 此为psql独有的错误&#xff0c;不能对特殊字符’/u0000’,进行序列化&#xff0c;需要将此特殊字符替…

webrtc中的接口代理框架

文章目录 接口代理框架Proxy体系类结构导出接口 webrtc的实际运用PeerConnectionFactoyPeerConnection使用 接口代理框架 webrtc体系庞大&#xff0c;模块化极好&#xff0c;大多数模块都可以独立使用。模块提供接口&#xff0c;外部代码通过接口来使用模块功能。 在webrtc中通…

uni-app 前后端调用实例 基于Springboot

锋哥原创的uni-app视频教程&#xff1a; 2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中...共计23条视频&#xff0c;包括&#xff1a;第1讲 uni…

《PCI Express体系结构导读》随记 —— 第I篇 第2章 PCI总线的桥与配置(1)

前言中曾提到&#xff1a;本章重点介绍PCI桥。 在PCI体系结构中含有两类桥&#xff1a;一类是HOST主桥&#xff1b;另一类是PCI桥。在每一个PCI设备中&#xff08;包括PCI桥&#xff09;&#xff0c;都含有一个配置空间。这个配置空间由HOST主桥管理&#xff0c;而PCI桥可以转…

cfa一级考生复习经验分享系列(十五)

备考背景&#xff1a; 本科211石油理科背景&#xff1b;无金融方面专业知识及工作经验&#xff1b;在职期间备考&#xff1b;有效备考时间2个月&#xff1b;12月一级考试10A。 复习进度及教材选择 首先说明&#xff0c;关于教材的经验分享针对非金融背景考生。 第一阶段&#x…

Java EE Servlet之Cookie 和 Session

文章目录 1. Cookie 和 Session1.1 Cookie1.2 理解会话机制 (Session)1.2.1 核心方法 2. 用户登录2.1 准备工作2.2 登录页面2.3 写一个 Servlet 处理上述登录请求2.4 实现登录后的主页 3. 总结 1. Cookie 和 Session 1.1 Cookie cookie 是 http 请求 header 中的一个属性 浏…

[枚举涂块]画家问题

画家问题 题目描述 有一个正方形的墙&#xff0c;由N*N个正方形的砖组成&#xff0c;其中一些砖是白色的&#xff0c;另外一些砖是黄色的。Bob是个画家&#xff0c;想把全部的砖都涂成黄色。但他的画笔不好使。当他用画笔涂画第(i, j)个位置的砖时&#xff0c; 位置(i-1, j)、…

劫持 PE 文件:新建节表并插入指定 DLL 文件

PE格式简介 PE(Portable Executable)格式&#xff0c;是微软Win32环境可移植可执行文件(如exe、dll、vxd、sys和vdm等)的标准文件格式。PE格式衍生于早期建立在VAX(R)VMS(R)上的COFF(Common Object File Format)文件格式。 Portable 是指对于不同的Windows版本和不同的CPU类型上…

UIToolKit使用心得

起因 因为那个uitoolkit自己写了一套graphView&#xff0c;所以想着来用用但是用完之后发现也不过如此 怎么构建自己的组件 我在继承Node之后想修改node的样式该怎么办呢是这样的。先用pick点击默认的node节点元素- 在pick默认创建的node节点之后&#xff0c;可以把它的uxml…