Linux 线程的属性 线程池 多线程的创建
线程的属性
引入
我们设想一个场景,使用pthread_detach时,发现线程早就已经结束了,这时候pthread_detach还能正常发挥清理线程的 独有空间 的作用吗?
答案是可以的,但是这难免是一个 程序设计上的一个小缺陷,虽不影响结果,但是总是让人感到困惑。为了解决这一问题,我们可以在 线程属性 中进行对应设置。下面我们来学习一下如何操作线程属性吧!
这里再次提醒,当我们属性设置了detach或者调用了pthread_detach后,就不可以再使用pthread_join函数了。
介绍
typedef struct
{
int etachstate; //线程的分离状态
int schedpolicy; //线程调度策略
struct sched_param schedparam; //线程的调度参数
int inheritsched; //线程的继承性
int scope; //线程的作用域
size_t guardsize; //线程栈末尾的警戒缓冲区大小
int stackaddr_set; //线程的栈设置
void* stackaddr; //线程栈的位置
size_t stacksize; //线程栈的大小
} pthread_attr_t;
可以看到,线程属性是一个结构体,其中包含的成员也有很多,但查看和修改步骤都大同小异,下面我主要向大家展示 分离状态 和 栈 属性的 查看和修改。
线程属性设置API
初始化线程属性函数:
int pthread_attr_init(pthread_attr_t *attr);
函数返回值:
成功:0;
失败:错误号
销毁线程属性所占用的资源函数:
int pthread_attr_destroy(pthread_attr_t *attr);
函数返回值:
成功:0;
失败:错误号
设置线程属性,分离or非分离
1 int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
获取程属性,分离or非分离
1 int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstat);
参数:
attr:已初始化的线程属性
detachstate: 分离状态
PTHREAD_CREATE_DETACHED(分离线程)
PTHREAD_CREATE_JOINABLE(非分离线程)
线程设置的步骤
1、获取
2、修改
3、设置
代码练习
cpp
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define SIZE 128
void *th_fun(void *arg)
{
while (1)
sleep(1);
}
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_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)
{
perror("pthread_create");
_exit(-1);
}
printf("%d\n", i++);
sleep(1);
}
pthread_attr_destroy(&attr);
return 0;
}
代码运行结果

我们可以看到主线程正常运行,说明子线程,线程已经是 分离状态了。
在这里,我想向大家引入一下进程池的概念。
在上面这个例子中,大家可以看到我是在堆区 为栈 申请的空间,这样的好处是,堆区空间较大可以增加一个进程中最大可容纳的线程数目,但是堆区再大,也会有被用完的时候,并且这里 线程申请的空间你不释放,就永远不会归还给系统,相当于一块空间只是用一次,空间资源利用率较低,因此为了提高线程的最大容纳数目和提高空间利用率,线程池就这样诞生了:
线程池
这里我简单提一下,大家心里有数就行:
我们把在一个区域内,存放着多个线程,我们可以从这个里取线程,但用完需要归还,这样当我们取和还的数目近似时,几乎就可以无限使用;而不是像现在一样用了不还,只能等到线程回收。并且这个区域还有一个功能是会根据你的任务数量变化去设置区域中的线程的数目。而这个区域就是线程池。
线程池我之后会详细介绍,这里大家只需知道这个概念即可。
多线程案例
需要实现的功能
输入线程名,该与线程执行的时间。对应的线程就会执行对应时间长度,并且可以在线程运行期间,加入其他线程,多个线程一起运行。
cpp
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char task_name[32];
int time;
} MSG;
void *deal_fun(void *arg)
{
MSG msg = *(MSG *)arg;
int i = 0;
for (i = msg.time; i > 0; i--)
{
printf("%s剩余时间%d\n", msg.task_name, i);
sleep(1);
}
return NULL;
}
int main(int argc, char const *argv[])
{
while (1)
{
MSG msg;
printf("输入新增的任务名:");
fgets(msg.task_name, sizeof(msg.task_name), stdin);
msg.task_name[strlen(msg.task_name) - 1] = 0;
printf("输入运行时间:");
scanf("%d", &msg.time);
getchar(); // 获取换行符
pthread_t tid;
pthread_create(&tid, NULL, deal_fun, (void *)&msg);
pthread_detach(tid); // 线程分离
}
return 0;
}
代码运行结果

结束
代码重在练习!
代码重在练习!
代码重在练习!
今天的分享就到此结束了,希望对你有所帮助,如果你喜欢我的分享,请点赞收藏夹关注,谢谢大家!!!
博客内容源自课堂笔记,因此偏向于教学,适合新人学习 和 大佬复习,感谢你的阅读!