线程的属性 —— 分离的状态(detached state)、栈地址(stack address)、栈大小(stack size)

2023-10-31

参考:(四十二)线程——线程属性
作者:FadeFarAway
发布时间:2017-01-17 14:09:55
网址:https://blog.csdn.net/FadeFarAway/article/details/54576771

引入

linux下线程的属性是可以根据实际项目需要,进行设置。之前我们讨论的线程都是采用线程的默认属性,默认属性已经可以解决绝大多数开发时遇到的问题。如我们对程序的性能提出更高的要求那么需要设置线程属性,比如可以通过设置线程栈的大小来降低内存的使用,增加最大线程个数

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_attr_init,这个函数必须在pthread_create函数之前调用。之后须用pthread_attr_destroy函数来释放资源

线程属性主要包括:分离的状态(detached state)、栈地址(stack address)、栈尺寸(stack size)、优先级(priority)、作用域(scope)、调度策略和参数(scheduling policy and parameters)。

默认的属性为:非绑定、非分离、缺省M的堆栈、与父进程同样级别的优先级。

线程属性初始化

  先初始化线程属性,再使用pthread_create创建线程。

#include <pthread.h>

int pthread_attr_init(pthread_attr_t *attr); //初始化线程属性
int pthread_attr_destroy(pthread_attr_t *attr); //销毁线程属性所占用的资源

一、线程的分离状态(detached state)

线程的分离状态决定一个线程以什么样的方式来终止自己:

  • 非分离状态:线程的默认属性是非分离状态,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。

  • 分离状态:分离线程没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。

应该根据自己的需要,选择适当的分离状态。

线程分离状态的函数:

#include <pthread.h>

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); // 设置线程属性,分离or非分离
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate); // 获取线程属性,分离or非分离

pthread_attr_t *attr:被已初始化的线程属性
int *detachstate:可选为PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE_JOINABLE(非分离线程)

【要注意的一点】如果设置一个线程为分离线程,而这个线程运行又非常快,它很可能在pthread_create函数返回之前就终止了,它终止以后就可能将线程号和系统资源移交给其他的线程使用,这样调用pthread_create的线程就得到了错误的线程号。要避免这种情况可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用pthread_cond_timedwait函数,让这个线程等待一会儿,留出足够的时间让函数pthread_create返回。设置一段等待时间,是在多线程编程里常用的方法。但是注意不要使用诸如wait()之类的函数,它们是使整个进程睡眠,并不能解决线程同步的问题

Demo

/*
 *#include <pthread.h>
 *int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
 *                              //设置线程属性,分离or非分 离
 *int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
 *                              //获取程属性,分离or非分离
 *  
 *pthread_attr_t *attr:被已初始化的线程属性
 *int *detachstate:可选为PTHREAD_CREATE_DETACHED(分离线程)
 *                 和PTHREAD _CREATE_JOINABLE(非分离线程)
 */
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>

void *th_fun(void *arg)
{
    int n = 15;
    while(n--)
    {
        printf("%x  %d\n",(int)pthread_self(), n);
        sleep(1);
    }
    return (void *)1;//由于被设置为分离态所以这个返回值不能被获取
}

int main(void)
{
    pthread_t tid;
    pthread_attr_t attr;  //保存线程的属性,现在里面是垃圾值
    int err;

    pthread_attr_init(&attr);// 初始化线程属性结构体,初始化之后就保存着线程属性的默认值

    //参考上面,先调用初始化函数(pthread_attr_init)之后才能设置线程属性
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); //设置为分离线程

    // 创建线程,注意第二个参数
    pthread_create(&tid, &attr, th_fun, NULL);

    //因为分离了所以会出现Invalid argument非法的参数
    err = pthread_join(tid, NULL);
    while(1)
    {
        if(err != 0)
        {
            printf("%s\n",strerror(err));
            sleep(10);
            pthread_exit((void *)1);
        }
    }
    pthread_attr_destroy(&attr);//销毁线程属性所占用的资源
    return 0;
}

运行结果:
在这里插入图片描述

二、线程的栈地址(stack address)

  POSIX.1定义了两个常量_POSIX_THREAD_ATTR_STACKADDR 和_POSIX_THREAD_ATTR_STACKSIZE 检测系统是否支持栈属性。也可以给sysconf函数传递_SC_THREAD_ATTR_STACKADDR或 _SC_THREAD_ATTR_STACKSIZE来进行检测。

栈有一个默认大小(点击查看博文),当进程栈地址空间不够用时,指定新建线程使用由malloc分配的空间作为自己的栈空间。通过pthread_attr_setstackaddr和pthread_attr_getstackaddr两个函数分别设置和获取线程的栈地址。传给pthread_attr_setstackaddr函数的地址是缓冲区的低地址(不一定是栈的开始地址,栈可能从高地址往低地址增长)。

#include <pthread.h>

int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr);
int pthread_attr_getstackaddr(pthread_attr_t *attr, void **stackaddr);

attr: 指向一个线程属性的指针
stackaddr: 返回获取的栈地址
返回值:若是成功返回0,否则返回错误的编号

说 明:pthread_attr_getstackaddr函数已过时,一般用下面讲到的pthread_attr_getstack来代替

三、线程的栈大小(stack size)

  当系统中有很多线程时,可能需要减小每个线程栈的默认大小,防止进程的地址空间不够用;当线程调用的函数会分配很大的局部变量或者函数调用层次很深时,可能需要增大线程栈的默认大小。
  函数pthread_attr_getstacksize和 pthread_attr_setstacksize提供获取和设置。

#include <pthread.h>

int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);

attr 指向一个线程属性的指针
stacksize 返回线程的堆栈大小
返回值:若是成功返回0,否则返回错误的编号

除上述对栈设置的函数外,还有以下两个函数可以获取和设置线程栈属性(上面的一组在现在的开发过程中往往不会使用

#include <pthread.h>

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);

attr 指向一个线程属性的指针
stackaddr 返回获取的栈地址
stacksize 返回获取的栈大小
返回值:若是成功返回0,否则返回错误的编号

Demo

/*
 * 获取和设置线程的栈大小
 * #include <pthread.h>
 * 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);
 * attr 指向一个线程属性的指针
 * stackaddr 返回获取的栈地址
 * stacksize 返回获取的栈大小
 * 返回值:若是成功返回0,否则返回错误的编号
 */
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>

#define SIZE 0x10000

int print_ntimes(char *str)
{
    sleep(1);
    printf("%s\n", str);
    return 0;
}

void *th_fun(void *arg)
{
    int n = 3;
    while (n--)
        print_ntimes("hello xwp\n");//在线程中也可以调用别的函数
}

int main(void)
{
    pthread_t tid;
    int err, detachstate, i = 1;
    pthread_attr_t attr;
    size_t stacksize;
    void *stackaddr;

    pthread_attr_init(&attr);//初始化线程属性

    pthread_attr_getstack(&attr, &stackaddr, &stacksize);//获取栈信息
    printf("stackadd=%p\n", stackaddr);         //打印栈的地址
    printf("stacksize=%x\n", (int)stacksize);   //打印栈的大小

    /*获取当前线程是否为分离属性*/
    pthread_attr_getdetachstate(&attr, &detachstate);
    if (detachstate == PTHREAD_CREATE_DETACHED)
        printf("thread detached\n");
    else if (detachstate == PTHREAD_CREATE_JOINABLE)
        printf("thread join\n");
    else
        printf("thread un known\n");

    /* 设置线程分离属性*/
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    while (1)
    {
        /* 在堆上申请内存,指定线程栈的起始地址和大小*/
        stackaddr = malloc(SIZE);//为栈分配空间、返回首地址
        if (stackaddr == NULL)
        {
            perror("malloc");
            exit(1);
        }
        /* 设置栈大小和地址 大小为上面的宏,位置为上面设置的*/
        stacksize = SIZE;//设置占空间大小
        pthread_attr_setstack(&attr, stackaddr, stacksize);       //线程属性 栈地址  栈大小

        err = pthread_create(&tid, &attr, th_fun, NULL);//创建线程
        if (err != 0)
        {
            printf("%s\n", strerror(err));
            exit(1);
        }

        printf("%d\n", i++);
    }
    pthread_attr_destroy(&attr);//销毁线程属性所占用的资源
    return 0;
}

运行结果:

循环创建线程,每个线程分配占用堆空间大小0x10000,最终创建2145次线程时提示空间不足,也就是堆空间被占用尽(我自己理解的)。
在这里插入图片描述

在这里插入图片描述

细节注意

1. 主线程退出其他线程不退出,主线程应调用ptrhed_exit
2. 避免僵线程(可以使用一下的方法)

1、join
2、pthread_deatch
3、pthread_create指定分离属性
注:被join线程可能在join函数返回前就释放完自己的所有内存资源,所以不应当返回被回收线程栈中的值;

3. malloc和mmap申请的内存可以被其他线程释放
4. 如果线程终止时没有释放加锁的互斥量,则该互斥量不能再被使用
5. 应避免在多线程模型中调用fork除非,马上exec,子进程中只有调用fork的线程存在,其他线程在子进程中均pthread_exit
6. 信号的复杂语义很难和多线程共存,应避免在多线程引入信号机制

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

线程的属性 —— 分离的状态(detached state)、栈地址(stack address)、栈大小(stack size) 的相关文章

  • 十、C++11左值右值、左值引用、右值引用、万能引用、完美转发

    10 C 11左值右值 左值引用 右值引用 10 1 左值 右值 左值 可以在 左边使用的值 右值 只能在 右边使用的值 字面量 中间结果 临时对象 匿名对象 无法直接取地址 不能使用左值引用 10 2 左值引用 右值引用 实例 左值引用
  • 【hello Linux】Linux第一个小程序 - 进度条

    目录 先来区分两个标识符 回车和换行 1 倒计时 2 进度条 Linux 下面来编写Linux系统下的第一个小程序 进度条 先来区分两个标识符 回车和换行 r 和 n r 回车 代表回到本行的开头 n 换行 代表回到光标的下一行的光标处 我
  • 16LinuxC进程间通信之mmap创建匿名映射区

    1 mmap创建匿名映射区 1 创建匿名映射区非常简单 只需要加上MAP ANONYMOUS即可 参数len长度可以随便大小 fd没有传 1即可 open这些函数可以不需要了 并且匿名映射实际上就是解决中间创建的文件问题 2 并且 匿名映射
  • Linux·内核的 4 大 IO 调度算法

    Linux 内核包含4个IO调度器 分别是 Noop IO scheduler Anticipatory IO scheduler Deadline IO scheduler 与 CFQ IO scheduler anticipatory
  • linux系统函数总结(一)

    realpath include
  • 多线程下事务控制

    我篇文章 大数据批量新增or修改太慢太Low 线程池 CountDownLatch CompletableFuture完美解决 弊端就是无法实现事务控制 那么今天他就来啦 需求 大数据平台去获取数据 gt 通过对象组装 gt 插入到对应的表
  • 线程的三种实现方式

    一 继承Thread类 二 实现Runable接口 对于1 2两种方法应该都会知道的 即使在上java相关的课程中老师一般都会介绍这两种实现的方法 所以这里不赘述了 直接进入第三种第四种的实现方式 三 实现Callable接口 packag
  • 05LinuxC线程学习之练习循环创建多个子线程和线程传参大坑(可以对比之前循环创建多个子进程)

    注 1 之前循环创建多个子进程的文章 https blog csdn net weixin 44517656 article details 109433060 2 wait回收子进程并且获取正常退出的返回值和异常退出的信号值的文章 htt
  • MFC之AfxbeginThread 线程 创建、挂起、释放、结束、退出

    MFC之AfxbeginThread 线程 创建 挂起 释放 结束 退出 本文简单阐述了如何使用一个afxbeginthread创建一个线程 两种方法 使用默认设置 使用自主设置参数 以及一些如同 挂起 释放 边界锁等操作 h文件添加声明
  • QT 如何打印QThread线程id号

    qDebug lt lt DealTimeoutObject1 lt
  • Linux 系统编程之select

    Linux 系统编程之select select 允许单个程序监听多个文件描述符 直到一个或者多个文件描述符准备就绪不阻塞系统 常常用于解决阻塞型的程序 相关代码 According to POSIX 1 2001 include
  • 线程——一个计数器计数到100,在每个数字之间暂停1秒,每隔10个数字输出一个字符串

    16 一个计数器计数到100 在每个数字之间暂停1秒 每隔10个数字输出一个字符串 public class MyThread extends Thread public void run for int i 0 i lt 100 i if
  • Java的线程同步 & 并发操作

    并发 CUP在同一时间或同一时段内只能执行一件事情 而不同时件执行时 切换得十分快速 因为CUP的频率非常高 切换的速度人根本感受不出来 同步 同步是多个任务进行时 按照一定的规律进行着 线程并发 同一时间间隔中 有多个线程在同时执行 就是
  • 进程和线程的详解和区别

    1 进程和线程概述 我们都知道计算机的核心是CPU 它承担了所有的计算任务 而操作系统是计算机的管理者 它负责任务的调度 资源的分配和管理 统领整个计算机硬件 应用程序是具有某种功能的程序 程序是运行于操作系统之上的 2 进程 我们编写的代
  • Unity协程和线程的区别

    先简要说下结论 协同程序 coroutine 与多线程情况下的线程比较类似 有自己的堆栈 自己的局部变量 有自己的指令指针 IP instruction pointer 但与其它协同程序共享全局变量等很多信息 协程 协同程序 同一时间只能执
  • Linux进程编程(PS: exec族函数、system、popen函数)

    目录 1 进程相关概念 程序和进程 查看系统中的进程 ps指令 top指令 进程标识符 使用getpid 获取 父进程 子进程 2 创建进程fork 进程创建发生了什么 C程序的存储空间如何分配 3 创建进程vfork 区别fork 4 进
  • 【Linux学习笔记】7. Linux文件IO详解(附代码实例)

    Linux文件I O 前置知识 Linux文件I O分为系统IO和标准IO 常用于系统编程 系统I O通过文件描述符 fd 来操作文件 标准I O通过文件流 FILE 来操作文件 Linux下可以使用man命令来查看使用手册 学习和使用这些
  • Linux·进程权限控制

    Linux系统的安全性得益于其进程权限和文件权限的控制机制 今天抽空梳理下Linux下的进程权限控制相关的文件权限涉及一点 首先明确四个名词 真实用户ID real ID 有效用户ID effective ID 保存用户ID Saved I
  • 【java篇】线程安全问题(大总结)

    哎嘿 CSDN的大佬您来啦 这来都来了 浅浅的给个赞呗 系列文章目录 线程的创建与主要方法分析和其他基础知识点 可以参考以下文章 线程知识点总结 南斋孤鹤的博客 CSDN博客 线程知识 超全 线程知识点 及线程方面的一些理解性问题https
  • 【Linux】进程优先级,环境变量,进程地址空间

    文章目录 1 进程优先级 基本概念 查看系统进程 PRI and NI PRI vs NI 修改进程优先级的命令 其他概念 2 环境变量 基本概念 查看环境变量方法 常见环境变量 测试PATH 环境变量相关的命令 环境变量的组织方式 通过代

随机推荐

  • 成为一名Java架构师的必修课

    一 热门框架源码学习 设计模式篇 Spring5源码解读篇 Mybatis篇 SpringBoot2篇 二 微服务架构 架构设计篇 BAT互联网架构这些年的演进分析 国内外常见分布式系统架构状况介绍 微服务架构指南 领域驱动设计DDD模型
  • ESG评级能否促进企业绿色转型(2009-2021年)

    参照胡洁 2023 的做法 对来自数量经济技术经济研究 ESG评级能否促进企业绿色转型 基于多时点双重差分法的验证 一文中的基准回归部分进行复刻 本文从非正式环境规制视角出发 基于商道融绿首次公布上市公司 ESG 评级的外生冲击 以2009
  • URL编码与解码

    通常如果一样东西需要编码 说明这样东西并不适合传输 原因多种多样 如Size过大 包含隐私数据 对于Url来说 之所以要进行编码 是因为Url中有些字符会引起歧义 例如Url参数字符串中使用key value键值对这样的形式来传参 键值对之
  • vue在线预览word,pdf, xls,ppt 文档

    首先先踩坑 也不算坑 只是跟我的需求不匹配 一 官方渠道 使用微软提供的Office Online平台只需要一个网址即可在线查看Xls doc PPT等文档 http view officeapps live com op view asp
  • 第二个项目(第6210小时时进行)

    给老师演示过物理效果后 老师甚为满意 于是把我推荐给了他兼职的公司的老总 但是老总模棱两可的态度效果不佳 老师怕我不开心 告诉我 他这里项目多的做不完 于是进入了下一个项目 用到的工具是qt osg 老师写框架 我做模块
  • AOP切入同类调用方法-AopContext.currentProxy()

    本文链接 https blog csdn net u014788227 article details 90111662 常规使用spring的AOP功能 就是对一个service的B方法进行切入记录日志 AOP能起作用 但是假如B方法被s
  • Anaconda/pip常见命令

    目录 一 Conda使用 1 1 conda基础命令 1 2 添加第三方源 二 pip常见命令 一 Conda使用 1 1 conda基础命令 打开anaconda Prompt 输入conda list 就会显示已经安装好的库 如果这些库
  • 尿沉渣图像处理——有形成分边缘检测

    有形成分边缘检测 处理思路 1 将彩色图像灰度化 以去除图像冗余信息 2 使用中值滤波 以去除椒盐噪声 3 邻域滤波 使图像模糊 以便于去除刻度框阴影 4 Canny算法与Sobel算法边缘检测后叠加平均 使细胞可形成连通域 5 孔洞填充
  • html sql连接mysql数据库_HTML连接sql数据库

    怎样从HTML网页中获取SQL数据库里的数据 我现在是一名学生 第一学期快结束了 老师要CSS布局HTML小编今天和大家分享我们每个学习小组用C 做HTML是无法读取数据库的 HTML是页面前端脚本语言 要想从HTML网页中获取SQL数据库
  • GitLab在项目的环境搭建和基本的使用

    目录 gitlab 使用入门 1 导读 本教程主要讲解了GitLab在项目的环境搭建和基本的使用 可以帮助大家在企业中能够自主搭建GitLab服务 并且可以GitLab中的组 权限 项目自主操作 GitLab简介 GitLab环境搭建 Gi
  • mongo-删除重复数据

    mongo 删除重复数据 使用aggregate聚合查询重复数据 group中是查询条件 根据你的字段来聚合相同的数据 count用来统计重复出现的次数 match来过滤没有重复的数据 db getCollection 你的集合名 aggr
  • Object.assign是浅拷贝还是深拷贝?

    话不多说先举个例子 let source a 1 let target Object assign source console log target a 1 source a 2 console log source a 2 consol
  • VMware Tools 启动脚本未能在虚拟机中成功运行。如果您在此虚拟机中配置了自定义启动脚本,请确保该脚本没有错误。您也可以提交支持请求,报告此问题。...

    第一步 sudo apt get autoremove open vm tools 第二步 sudo apt get install open vm tools desktop 然后重启 转载于 https www cnblogs com
  • qt实现简单的聊天页面(纯页面)

    我是模仿qq页面来做的 这是效果图 很简陋 基础的一些部分都比较简单 写一些对我来讲是难点或者有意思的东西吧 记录一些 1 这里的 开心 是使用painter画上去的 因为右边已经有图标了 所以不太好使用QLabel来进行绘制 QPaint
  • MacBook外接显示器设置方法(新手入门贴)

    小屏幕的MacBook MacBook Pro放在桌上长时间使用 眼睛比较累 而且 长时间低头看屏幕 易得颈椎病 绝对有损健康 配一台大屏幕的外置显示器不失为两全其美的好办法 首先 得买一台中意的大屏幕LED显示器 废话undefined
  • steam植物大战僵尸汉化补丁使用教程

    植物大战僵尸作为小时候印象最深的游戏之一 上线便收获了一大波人的喜爱与好评 仍至今日 还有许多小伙本们沉浸其中 不过steam版本并不支持简体中文语言 网络上面虽然一大堆但都是很久之前的 会出现一些黑屏的问题 所以小编此次带来了steam植
  • ILSVRC竞赛详细介绍(ImageNet Large Scale Visual Recognition Challenge)

    ILSVRC ImageNet Large Scale Visual Recognition Challenge 是近年来机器视觉领域最受追捧也是最具权威的学术竞赛之一 代表了图像领域的最高水平 ImageNet数据集是ILSVRC竞赛使用
  • QT使用ODBC连接MySQL

    本文主要讲述QT使用ODBC连接MySQL数据库的过程 第一步 下载连接工具 链接如下 https cdn mysql com Downloads Connector ODBC 8 0 mysql connector odbc 8 0 28
  • vmware17:下载安装

    1 访问vm官网下载vm17安装包 下载 VMware Workstation Pro CN 选择windows下载 下载成功后 双击装包安装 直接下一步安装 勾选接受许可条款下一步 更改安装路径 继续下一步 最后点击安装 最后等待完成输入
  • 线程的属性 —— 分离的状态(detached state)、栈地址(stack address)、栈大小(stack size)

    参考 四十二 线程 线程属性 作者 FadeFarAway 发布时间 2017 01 17 14 09 55 网址 https blog csdn net FadeFarAway article details 54576771 目录 引入