(1)线程属性初始化与销毁
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
1.pthread_attr_init对象对属性对象的内存空间时动态分配的
2.pthread_attr_destroy函数会释放动态分配的内存
3.pthread_attr_destroy函数会用无效的值初始化attr对象
(2)线程属性
名称 描述
datachstate 线程的分离状态属性
guardsize 线程栈末尾的警戒缓冲区大小(字节数)
stackaddr 线程栈的最低地址
stacksize 线程栈的最小长度(字节数)
(3)设置/获取线程的分离状态属性
pthread_attr_getdetachstatte(const pthread_attr_t *attr, int *detachstate);
pthread_attr_setdetachstatte(const pthread_attr_t *attr, int *detachstate);
detachstate为以下两个值:
PTHREAD_CREATE_DETACHED // 创建分离线程
PTHREAD_CREATE_JOINABLE // 创建可回收线程
(4)线程栈属性
注意:在编译阶段应该使用下面两个宏来检测系统是否支持线程栈属性,也可以将下面两个宏传给sysconf函数来检查
_POSIX_THREAD_ATTR_STACKADDR
_POSIX_THREAD_ATTR_STACKSIZE
(1)概述
1.对进程来说,一个进程只有一个栈(虚地址空间)。进程栈的大小通常不是问题
2.对线程来说,多个线程共享进程栈空间。
每个线程瓜分进程栈的一部分来作为自己的线程栈,而不是混合一起使用。
3.如果创建的线程过多,线程栈总数超过了进程的栈地址空间,就需要减小默认的线程栈的大小。
4.如果单个线程需要使用的栈空间超过了默认大小,就需要为线程分取更多的空间。
(2)获取和设置线程栈的地址空间
int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize);
int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
[1] 当进程栈的虚地址空间被线程用完了时,新线程需要分配新的空间来作为线程的栈空间。
1.新分配的地址空间必须与“系统页地址”对齐
可通过下面的函数来分配:
posix_memalign(&sp, sysconf(_SC_PAGESIZE), stack_size)
2.通过pthread_attr_setstack函数来设置线程栈的地址空间
stackaddr: 1.新建线程栈的最低可寻址地址, 该地址应与系统的页地址对齐
2.栈由下往上增长时, stackaddr表示栈顶未知; 反之为栈底位置。
stacksize:线程栈的大小
(3)获取和设置线程栈的大小
如果只希望改变默认的线程栈大小,但是又不想自己处理线程栈的空间分配问题时,调用pthread_attr_setstacksize函数进行测试。
int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);
// 获取attr中配置的栈大小,并保存到stacksize中
注意: 该函数并不是获取调用线程的栈大小
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
// 将stacksize指示的线程栈大小设置到stacksize中。
注意: 该函数并不是设置调用线程的栈大小
(4)获取指定线程thread的属性
int pthread_getattr_np(pthread_t thread, pthread_attr_t *attr);
注意: 该函数是非GUN标准函数的扩展
(5)设置/获取线程栈末尾之后 用以避免栈溢出的扩展内存的大小
int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize);
int pthread_attr_setguardsize(const pthread_attr_t *attr, size_t guardsize);
注意: 1.如果guardsize被改变,操作系统可能会把它取为页大小的整数倍
2.如果线程的栈溢出到警戒区域,应用程序就可能通过信号接收到出错信息
测试代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/wait.h>
#include <sys/acct.h>
#include <errno.h>
#include <sys/times.h>
#include <pthread.h>
#include <signal.h>
void *pstart(void *arg)
{
return (void *)0;
}
int mypthread_attr_setdetachstate(pthread_attr_t *attr)
{
// int joinable = PTHREAD_CREATE_JOINABLE;
return pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);
}
int mypthread_attr_getdetachstate(const pthread_attr_t *attr)
{
//int detachstate = PTHREAD_CREATE_DETACHED;
int joinable;
int re= pthread_attr_getdetachstate(attr, &joinable);
if (re !=0)
return -1;
else {
if (joinable == PTHREAD_CREATE_DETACHED)
printf("attr==PTHREAD_CREATE_DETACHED\n");
else if (joinable == PTHREAD_CREATE_JOINABLE)
printf("attr==PTHREAD_CREATE_JOINABLE\n");
else
return -1;
}
return re;
}
void *start_test_stacksize(void *arg)
{
pthread_attr_t attr;
size_t stacksize;
pthread_attr_init(&attr);
pthread_getattr_np(pthread_self(), &attr); // 获取当前线程的属性
pthread_attr_getstacksize(&attr, &stacksize); // 读取attr中线程栈的大小
printf("start_test_stacksize: stacksize = %lu\n", stacksize); // 4M=4198400
return (void *)0;
}
// 测试线程栈大小设置
void threadattr_stacksize_test()
{
static pthread_attr_t attr_4m;
size_t stacksize;
pthread_t tid1;
// 获取线程栈的大小
pthread_attr_init(&attr_4m);
if (pthread_attr_setstacksize(&attr_4m, 4*1024 *1024) !=0 ) // 设置attr里的线程栈大小为4M=4198400
{
perror("ERROR: pthread_attr_setstacksize\n");
exit(-1);
}
pthread_attr_getstacksize(&attr_4m, &stacksize);
printf("threadattr_stacksize_test: stacksize = %lu\n", stacksize); //attr: 8388608=8M(默认大小)
//PTHREAD_STACK_MIN
pthread_create(&tid1, &attr_4m, start_test_stacksize,NULL);
//pthread_attr_destroy(&attr);
}
// 测试线程栈空间配置
void *start_test_stack(void *arg)
{
pthread_attr_t attr;
size_t stacksize;
void *stackaddr;
pthread_attr_init(&attr);
pthread_getattr_np(pthread_self(), &attr); // 获取当前线程的属性
pthread_attr_getstack(&attr, &stackaddr, &stacksize); // 读取attr中线程栈的大小
printf("start_test_stack: stackaddr=%p, stacksize =%lu\n", stackaddr, stacksize); // pagesize=4194304=4M
return (void *)0;
}
void threadattr_stack_test()
{
static void *sp = NULL;
static pthread_attr_t attr_pages; // 线程栈
static pthread_t tid2;
int stacksize;
int ret;
pthread_attr_init(&attr_pages);
long int pagesize = sysconf(_SC_PAGESIZE); // 系统页地址大小
printf("pagesize = %ld\n", pagesize); // 4096
stacksize = 4*1024 *1024; // 4M
// pthread_attr_setstack函数要求线程栈开始地址为页地址的整数倍
ret = posix_memalign(&sp, pagesize, stacksize); // 按页地址对其, 大小为4194304
if (ret != 0){
printf("ERROR: posix_memalign\n");
exit(0);
}
else
printf("posix_memalign() allocated at %p\n", sp);
if (pthread_attr_setstack(&attr_pages, sp, stacksize) != 0)
{
perror("ERROR: pthread_attr_setstack\n");
exit(-1);
}
pthread_create(&tid2, &attr_pages, start_test_stack, NULL);
}
void *start_test_guardsize(void *arg)
{
pthread_attr_t attr;
size_t guardsize;
pthread_attr_init(&attr);
pthread_getattr_np(pthread_self(), &attr); // 获取当前线程的属性
pthread_attr_getguardsize(&attr, &guardsize); // 读取attr中线程栈末尾警戒区域的大小
printf("start_test_guardsize: guardsize =%lu\n", guardsize); 12288 = 12K
return (void *)0;
}
void threadattr_guardsize_test()
{
static pthread_attr_t attr; // 线程栈
static pthread_t tid3;
int guardsize;
long int pagesize = sysconf(_SC_PAGESIZE); // 系统页地址大小=4096
guardsize = pagesize *3; // 4096*3 = 12k, 必须为页地址的整数倍
pthread_attr_init(&attr);
if (pthread_attr_setguardsize(&attr, guardsize) != 0)
{
perror("ERROR: pthread_attr_setguardsize\n");
exit(-1);
}
pthread_create(&tid3, &attr, start_test_guardsize, NULL);
}
int main(int argc, char **argv)
{
#if 1
// 1. 设置/获取线程的分离状态属性
pthread_attr_t attr;
int error;
pthread_t tid;
pthread_attr_init(&attr);
mypthread_attr_getdetachstate(&attr); // PTHREAD_CREATE_JOINABLE
mypthread_attr_setdetachstate(&attr);
mypthread_attr_getdetachstate(&attr); // PTHREAD_CREATE_DETACHED
#endif
// 判断系统是否支持线程栈操作
#if defined(_POSIX_THREAD_ATTR_STACKADDR) || defined(_POSIX_THREAD_ATTR_STACKADDE)
printf("The system supports thread stack propertie\n");
// 2. 测试仅仅设置/获取线程栈的大小,不处理线程栈的地址空间分配问题
threadattr_stacksize_test();
// 3. 测试线程栈的地址空间分配和设置和获取
threadattr_stack_test();
// 4. 设置和获取线程栈的临界区域
threadattr_guardsize_test();
#else
printf("ERROR: The system cant't supports thread stack propertie\n");
#endif
pause();
return 0;
}