一次性初始化:
用途: 有些事需要且只能执行一次(比如互斥量初始化)。通常当初始化应用程序时,可以比较容易地将其放在main函数中。但当你写一个库函数时,就不能在main里面初始化了,你可以用静态初始化,但使用一次初始(pthread_once_t)会比较容易些。
用法:
//首先要定义一个pthread_once_t变量,这个变量要用宏PTHREAD_ONCE_INIT初始化。
//然后创建一个与控制变量相关的初始化函数
pthread_once_t once_control = PTHREAD_ONCE_INIT;
void init_routine( )
{
//需要初始化的内容
......
}
//最后,在任何时刻调用pthread_once函数。
//在多线程编程环境下,init_routine()函数仅执行一次,究竟在哪个线程中执行是不定的,由内核调度来决定。
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));
线程的属性:
线程的属性类型:pthread_attr_t
属性名称 | 描述 |
detachstate | 线程的分离状态 |
guardsize | 线程栈末尾的警戒区域大小(字节数) |
stacksize | 线程栈的最低地址 |
stacksize | 线程栈的大小(字节数) |
1、线程属性初始化
int pthread_attr_init(pthread_attr_t *attr);
2、线程属性销毁
int pthread_attr_destroy(pthread_attr_t *attr);
线程的分离属性:
1、分离属性的概念
分离一个正在运行的线程并不影响它,仅仅是通知当前系统该线程结束时,其所属的资源可以回收。一个没有被分离的线程在终止时会保留它的虚拟内存,包括他们的堆栈和其他系统资源,有时这种线程被称为“僵尸线程”。创建线程时默认是非分离的
如果线程具有分离属性,线程终止时会被立刻回收,回收将释放掉所有在线程终止时未释放的系统资源和进程资源。包括保存线程返回值的内存空间、堆栈、保存寄存器的内存空间等
2、分离属性的使用方法
如果在创建线程的时候就知道不需要了解线程的终止状态,那么可以修改pthread_attr_t结构体的detachstate属性,让线程以分离状态启动。
//设置线程分离属性的步骤
//1、定义线程属性变量
pthread_attr_t attr
// 2、初始化attr
pthread_attr_init(&attr)
//3、设置线程的分离状态属性
//线程的分离属性有两种合法值:PTHREAD_CREATE_DETACHED分离的 PTHREAD_CREATE_JOINABLE 非分离的,可连接的
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
//4、创建线程
int pthread_create(&tid, &attr, thread_fun, NULL)
获得线程的分离状态属性
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
线程的栈属性:
1、线程的栈大小
对于进程来说,虚拟地址空间的大小是固定的,进程中只有一个栈,因此它的大小通常不是问题。但对线程来说,同样的虚拟地址被所有的线程共享。如果应用程序使用了太多的线程,致使线程栈累计超过可用的虚拟地址空间,这个时候就需要减少线程默认的栈大小。另外,如果线程分配了大量的自动变量或者线程的栈帧太深,那么这个时候需要的栈要比默认的大。因此就需要修改线程栈的属性来适应具体程序的需要。
>检查系统是否支持线程栈属性
1)在编译阶段使用 _POSIX_THREAD_ATTR_STACKADDR 和 _POSIX_THREAD_ATTR_STACKSIZE符号
来检查系统是否支持线程栈属性,这些宏定义在/usr/include/bits/posix_opt.h
2)在运行阶段把 _SC_THREAD_ATTR_STACKADD和 _SC_THREAD_THREAD_ATTR_STACKSIZE
传递给sysconf函数检查系统对线程栈属性的支持。
如果用完了虚拟地址空间,可以使用malloc或者mmap来为其他栈分配空间,并修改栈的位置。
>修改栈属性
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);
也可以单独获取或者修改栈的大小,而不去修改栈的地址。栈大小设置,不能小于PTHREAD_STACK_MIN(需要头文件limit.h)
>修改栈大小
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
>获取栈大小
int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);
2、栈尾警戒区
线程属性guardsize控制着线程栈末尾以后用以避免栈溢出的扩展内存的大小,这个属性默认是PAGESIZE个字节。你可以把它设为0,这样就不会提供警戒缓冲区。同样的,如果你修改了stackaddr,系统会认为你自己要管理栈,警戒缓冲区会无效
1)、设置guardsize
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
2)、获取guardsize
int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize);
实例:
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<limits.h>
pthread_attr_t attr;
void *thread_1(void * arg)
{
long signed int stacksize;
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
pthread_attr_getstacksize(&attr,&stacksize);
printf("thread1: default stacksize is %ld\n",stacksize);
pthread_attr_setstacksize(&attr,100000);
pthread_attr_getstacksize(&attr,&stacksize);
printf("thread1: personic stacksize is %ld\n",stacksize);
pthread_attr_setstacksize(&attr,PTHREAD_STACK_MIN);
pthread_attr_getstacksize(&attr,&stacksize);
printf("thread1: minimum stacksize is %ld\n",stacksize);
#endif
printf("I am thread1\n");
return (void *)1;
}
void *thread_2(void * arg)
{
printf("I am thread2\n");
return (void *)2;
}
int main(int argc,char *argv[])
{
pthread_t tid1,tid2;
int err1,err2;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
//#ifdef _POSIX_THREAD_ATTR_STACKSIZE
// pthread_attr_setstacksize(&attr,PTHREAD_STACK_MIN);
//#endif
err1 = pthread_create(&tid1,&attr, thread_1,NULL);
err2 = pthread_create(&tid2,NULL, thread_2,NULL);
if(err1||err2)
{
printf("create thread fail\n");
return -1;
}
printf("thread1 return value is %d\n",pthread_join(tid1,NULL));
printf("thread2 return value is %d\n",pthread_join(tid2,NULL));
pthread_attr_destroy(&attr);
return 0;
}
运行结果:
binge@binge-HP-Compaq:~/my_share/pthread$ ./a.out
thread1 return value is 22
thread1: default stacksize is 8388608
thread1: personic stacksize is 100000
thread1: minimum stacksize is 16384
I am thread1
I am thread2
thread2 return value is 0