【多线程编程学习笔记13】线程属性有哪些,如何自定义线程属性?_c语言中文网thread(1)

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Golang全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注go)
img

正文

__schedpolicy 属性用于指定系统调度该线程所用的算法,它的值有以下 3 个:

  • SCHED_OTHER(默认值):分时调度算法;
  • SCHED_FIFO:先到先得(实时调度)算法;
  • SCHED_RR:轮转法;

其中,SCHED_OTHER 调度算法不支持为线程设置优先级,而另外两种调度算法支持。

<pthread.h> 头文件提供了如下两个函数,专门用于访问和修改 __schedpolicy 属性:

int pthread_attr_getschedpolicy(const pthread_attr_t , int * policy)
int pthread_attr_setschedpolicy(pthread_attr_
, int policy)

pthread_attr_getschedpolicy() 函数用于获取当前 __schedpolicy 属性的值;pthread_attr_setschedpolicy() 函数用于修改 __schedpolicy 属性的值。函数执行成功时,返回值为数字 0,反之返回非零数。

3) __schedparam

__scheparam 用于设置线程的优先级(默认值为 0),该属性仅当线程的 __schedpolicy 属性为 SCHED_FIFO 或者 SCHED_RR 时才能发挥作用。

<pthread.h> 头文件中提供了如下两个函数,用于获取和修改 __schedparam 属性的值:

int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);

其中,param 参数用于接收或者修改 __scheparam 属性的优先级,它是 sched_param 结构体类型的变量,定义在 <sched.h> 头文件中,内部仅有一个 sched_priority 整形变量,用于表示线程的优先级。函数执行成功时返回数字 0,反之返回非零数。

当需要修改线程的优先级时,我们只需创建一个 sched_param 类型的变量并为其内部的 sched_priority 成员赋值,然后将其传递给 pthrerd_attr_setschedparam() 函数。

不同的操作系统,线程优先级的值的范围不同,您可以通过调用如下两个系统函数获得当前系统支持的最大和最小优先级的值:

int sched_get_priority_max(int policy); //获得最大优先级的值
int sched_get_priority_min(int policy); //获得最小优先级的值

其中,policy 的值可以为 SCHED_FIFO、SCHED_RR 或者 SCHED_OTHER,当 policy 的值为 SCHED_OTHER 时,最大和最小优先级的值都为 0。

4) __inheritsched

新建线程的调度属性(____schedpolicy 和 __schedparam 属性)默认遵循父线程的属性(谁创建它,谁就是它的父线程),如果我们想自定义线程的调度属性,就需要借助 __inheritsched 属性。

也就是说,新线程的调度属性要么遵循父线程,要么遵循 myAttr 规定的属性,默认情况下 __inheritsched 规定新线程的调度属性遵循父线程,我们也可以修改 __inheritsched 的值,使新线程的调度属性遵循自定义的属性变量(如文章开头定义的 myAttr)规定的值。

<pthread.h> 头文件提供了如下两个函数,分别用于获取和修改 __inheritsched 属性的值:

//获取 __inheritsched 属性的值
int pthread_attr_getinheritsched(const pthread_attr_t *attr,int *inheritsched);
//修改 __inheritsched 属性的值
int pthread_attr_setinheritsched(pthread_attr_t *attr,int inheritsched);

其中在 pthread_attr_setinheritsched() 函数中,inheritsched 参数的可选值有两个,分别是:

  • PTHREAD_INHERIT_SCHED(默认值):新线程的调度属性继承自父线程;
  • PTHREAD_EXPLICIT_SCHED:新线程的调度属性继承自 myAttr 规定的值。

以上两个函数执行成功时返回数字 0,反之返回非零数。

5) __scope

线程执行过程中,可以只和同进程内的其它线程争夺 CPU 资源,也可以和系统中所有的其它线程争夺 CPU 资源,__scope 属性用于指定目标线程和哪些线程抢夺 CPU 资源。

<pthread.h> 头文件中提供了如下两个函数,分别用于获取和修改 __scope 属性的值:

//获取 __scope 属性的值
int pthread_attr_getscope(const pthread_attr_t * attr,int * scope);
//修改 __scope 属性的值
int pthread_attr_setscope(pthread_attr_t * attr,int * scope);

当调用 pthread_attr_setscope() 函数时,scope 参数的可选值有两个,分别是:

  • PTHREAD_SCOPE_PROCESS:同一进程内争夺 CPU 资源;
  • PTHREAD_SCOPE_SYSTEM:系统所有线程之间争夺 CPU 资源。

Linux系统仅支持 PTHREAD_SCOPE_SYSTEM,即所有线程之间争夺 CPU 资源。

当函数执行成功时,返回值为数字 0,反之返回非零数。

6) __stacksize

每个线程都有属于自己的内存空间,通常称为栈(有时也称堆栈、栈空间、栈内存等)。某些场景中,线程执行可能需要较大的栈内存,此时就需要我们自定义线程拥有的栈的大小。

__stacksize 属性用于指定线程所拥有的栈内存的大小。<pthread.h> 提供有以下两个函数,分别用于获取和修改栈空间的大小:

//获取当前栈内存的大小
int pthread_attr_getstacksize(const pthread_attr_t * attr,size_t * stacksize);
//修改栈内存的大小
int pthread_attr_setsstacksize(pthread_attr_t * attr,size_t * stacksize);

函数执行成功时,返回值为数字 0,反之返回非零数。

8) __guardsize

每个线程中,栈内存的后面都紧挨着一块空闲的内存空间,我们通常称这块内存为警戒缓冲区,它的功能是:一旦我们使用的栈空间超出了额定值,警戒缓冲区可以确保线程不会因“栈溢出”立刻执行崩溃。

__guardsize 属性专门用来设置警戒缓冲区的大小,<pthread.h> 头文件中提供了如下两个函数,分别用于获取和修改 __guardsize 属性的值:

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

pthread_attr_setguardsize() 函数中,设置警戒缓冲区的大小为参数 guardsize 指定的字节数。函数执行成功时返回数字 0,反之返回非零数。

实际应用

接下来通过一个样例,给大家演示如何自定义线程的属性:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
//myThread1 线程执行的函数
void Thread1(void arg)
{
printf(“Thread1 正在执行\n”);
printf(“http://c.biancheng.net\n”);
printf(“Thread1 执行完毕\n”);
return NULL;
}
//myThread2 线程执行的函数
void
Thread2(void
arg)
{
printf(“Thread2 正在执行\n”);
printf(“C语言中文网\n”);
printf(“Thread2 执行完毕\n”);
return NULL;
}
int main(int argc,char *argv[])
{
int num1, num2, res;
//创建两个线程
pthread_t mythread1, mythread2;
//创建两个表示线程优先级的变量
struct sched_param param1, param2;
//创建两个表示线程属性的变量
pthread_attr_t myAttr1, myAttr2;
//接收 2 个整数,用于设定线程的优先级
if (argc != 3) {
printf(“未向程序传入 2 个表示优先级的数字\n”);
return 0;
}
//初始化线程属性
res = pthread_attr_init(&myAttr1);
if (res != 0) {
printf(“myAttr1 init Fail\n”);
}

res = pthread_attr_init(&myAttr2);
if (res != 0) {
printf(“myAttr1 init Fail\n”);
}
//设置 myAttr1 的 __detachstate 属性值为 PTHREAD_CREATE_DETACHED
//遵循 myAttr1 属性的线程执行函数完毕后会自行释放占用私有资源,不支持 pthread_join() 函数
res = pthread_attr_setdetachstate(&myAttr1, PTHREAD_CREATE_DETACHED);
if (res != 0) {
printf(“myAttr1 set_detachstate Fail\n”);
}
//设置 myAttr1 的 __scope 属性值为 PTHREAD_SCOPE_SYSTEM
//遵循 myAttr1 属性的线程将同系统中的所有其它线程争夺 CPU 资源
res = pthread_attr_setscope(&myAttr1, PTHREAD_SCOPE_SYSTEM);
if (res != 0) {
printf(“myAttr1 set_scope Fail\n”);
}
//设置 myAttr2 的 __scope 属性值为 PTHREAD_SCOPE_SYSTEM
//遵循 myAttr2 属性的线程将同系统中的所有其它线程争夺 CPU 资源
res = pthread_attr_setscope(&myAttr2, PTHREAD_SCOPE_SYSTEM);
if (res != 0) {
printf(“myAttr2 set_scope Fail\n”);
}
//设置 myAttr1 的 __schedpolicy 属性值为 SCHED_FIFO
//系统会以实时调用的方式执行遵循 myAttr1 属性的线程
res = pthread_attr_setschedpolicy(&myAttr1, SCHED_FIFO);
if (res != 0) {
printf(“myAttr1 set_policy Fail\n”);
}

//设置 myAttr2 的 __schedpolicy 属性值为 SCHED_FIFO
//系统会以实时调用的方式执行遵循 myAttr2 属性的线程
res = pthread_attr_setschedpolicy(&myAttr2, SCHED_FIFO);
if (res != 0) {
printf(“myAttr2 set_policy Fail\n”);
}
//设置 myAttr1 的 __inheritsched 属性值为 PTHREAD_EXPLICIT_SCHED
//myAttr1 属性的线程将遵循自定义的线程属性
res = pthread_attr_setinheritsched(&myAttr1, PTHREAD_EXPLICIT_SCHED);
if (res != 0) {
printf(“myAttr1 set_inheritsched fail\n”);
}

//设置 myAttr2 的 __inheritsched 属性值为 PTHREAD_EXPLICIT_SCHED
//myAttr2 属性的线程将遵循自定义的线程属性
res = pthread_attr_setinheritsched(&myAttr2, PTHREAD_EXPLICIT_SCHED);
if (res != 0) {
printf(“myAttr2 set_inheritsched fail\n”);
}
//想 argv[] 数组中的字符转换为数字
num1 = atoi(argv[1]);
num2 = atoi(argv[2]);
// 分别将 num1 和 num2 作为线程优先级的值
param1.sched_priority = num1;
param2.sched_priority = num2;
//设置 myAttr1 属性的优先级为 param1
res = pthread_attr_setschedparam(&myAttr1, &param1);
if (res != 0) {
printf(“param1 setscheparam Fail\n”);
}
//设置 myAttr2 属性的优先级为 param2
res = pthread_attr_setschedparam(&myAttr2, &param2);
if (res != 0) {
printf(“param2 setscheparam Fail\n”);
}
//创建新线程并遵循 myAttr1 属性
res = pthread_create(&mythread1, &myAttr1, Thread1, NULL);
if (res != 0) {
printf(“mythread1 create Fail\n”);
}
//创建新线程并遵循 myAttr2 属性
res = pthread_create(&mythread2, &myAttr2, Thread2, NULL);

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
2 属性
res = pthread_create(&mythread2, &myAttr2, Thread2, NULL);

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-UWrRy5fM-1713178449550)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值