线程的高级属性
一次性初始化
有些时器需要且只能执行一次,比如互斥量初始化。如果库函数中有互斥量,使用一次初始会比较容易
一次性初始化 pthread_once_t变量,这个变量要用宏PTHREAD_ONCE_INIT初始化,然后创建一个与控制变量相关的初始化函数
pthread_once_t once_control = PTHREAD_ONCE_INIT;
void init-routine()
{
初始化互斥量
初始化读写锁
…
}
int pthread_once( pthread_once_t *once_contorl, void(*init_routine)(void));
多线程编译环境下,尽管 pthread_once出现在多个线程中国,但init_routine()函数只执行一次。
如果once-control初值为0 ,那么pthread_once 从未执行过,init_routine()函数会执行
如果once-control初值为1,则由于pthread_once都必须等待其中一个激发“已执行一次”信号,因此所有pthread_once()都会陷入永久等待,init_routine无法执行
如果once-control设为2,表示pthread_once已执行过一次,从而所有pthread_once都会立即返回,init_routine就没有际会之下
当pthread_once函数成功返回,once_control就会被设置为2.
#include "stdio.h"
#include "pthread.h"
#include "stdlib.h"
#include "signal.h"
#include "string.h"
#include "unistd.h"
pthread_once_t once =PTHREAD_ONCE_INIT;
void thread_init()
{
printf("i am in thread 0x%x\n",tid);
}
void *thread_fun1(void *arg)
{
tid =pthread_self;
printf("i am in thread 0x%x\n",tid);
printf("i am thread 0x%x\n",once); \\输出once是0
pthread_once(&once, thread_init);
printf("i am thread 0x%x\n",once); \\输出once是1
return NULL;
}
void *thread_fun2(void *arg)
{
sleep(2);
tid =pthread_self;
printf("i am in thread 0x%x\n",tid);
pthread_once(&once, thread_init);
return NULL;
}
int main()
{
pthread_t tid1,tid2;
int err;
err=pthread_create(&tid1,&attr,thread_fun1,NULL);
err=pthread_create(&tid2,NULL,thread_fun1,NULL);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
}
线程的属性
线程的属性有哪些
线程的属性用pthread_attr_t类型的结构表示
并不是所有系统都支持线程的这些属性,需要检查当前系统是否支持你设置的属性。
还有一些属性不包含在pthread_attr_t结构体中,如:线程的可取消状态,取消类型,并发度。
int pthread_attr_init(pthread_attrT *attr);
-线程属性初始化
int pthread_attr_destroy(pthread_attr_t *attr)
-线程属性销毁
1.线程销毁会释放初始化时申请的内存空间
2.销毁函数还会用无效的初值初始化pthread_attr_t 对象,因此如果该属性对象被误用,会导致线程创建失败。
线程的同步属性
也包含互斥量,读写锁,条件变量的属性
int pthread_mutexattr_init(pthreaed_mutexattr_t *attr);
-互斥量初始化
int pthread_mutexattr_destroy(pthreaed_mutexattr_t *attr);
-互斥量销毁
进程的共享属性有两种值
PTHREAD_PROCESS_PRIVATE
-默认值,同一个进程中的多个线程访问同一个同步对象
PTHREAD_PROCESS_PRIVATE
-使互斥量在多个进程中进行同步,如果互斥量在多进程的共享内存区域,那么具有这个属性的互斥量可以同步多进程
设置互斥量进程共享属性
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *resrtict attr, int *restrict pshared)
int pthread_mutexattr_setpshared(const pthread_mutexattr_t * attr, int pshared)
-进程共享属性通过检测宏_POSIX_THREAD_PROCESS_SHARED 得知系统是否支持
设置互斥量的类型属性
int othreaed_mutex_gettype(const pthread_mutexattr_t *restrict attr, int *restrict type);
int othreaed_mutex_settype(const pthread_mutexattr_t * attr, int *type);
例:
#include "stdio.h"
#include "pthread.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include "fcntl.h"
#include "sys/mman.h"
#include "sys/stat.h"
int main()
{
char *shm ="myshm";
char *shm1 ="myshm1";
int shm_id,shm_id1; //一个共享内存存放数据,一个共享内存存放互斥量
char *buf;
pid_t pid;
pthread_mutex_t *mutex; //互斥量
pthread_mutexattr_t mutexattr; //互斥量属性
shm_id1 = shm_open(shm1 ,O_RDWR|O_CREAT, 0644); //打开共享内存
ftruncate(shm_id1, 100);//调整共享内存的大小
mutex = (pthread_mutex_t *)mmap(NULL,100,PROT_READ|PROT_WRITE,MAP_SHARED,shm_id1,0);//映射共享内存MAP_SHARED属性表面对共享内存的修改会影响其他进程,若映射成功则返回映射区的内存起始地址给mutex
pthread_mutexattr_init(&mutexattr);
#ifdef _POSIX_THREAD_PROCESS_SHARED
pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED);
#endif
pthread_mutex_init(mutex, &mutexattr);
shm_id = shm_open(shm ,O_RDWR|O_CREAT, 0644);
ftruncate(shm_id, 100);
buf = (char *)mmap(NULL,100,PROT_READ|PROT_WRITE,MAP_SHARED,shm_id,0);
pid =fork();
if(pid==0)
{
sleep(1);//让父进程线运行
printf("i am child process\n");
pthread_mutex_lock(mutex);
memcpy(buf,"hello",6);
printf("child buf is :%s\n", buf);
pthread_mutex_unlock(mutex);
}
else if(pid>0)
{
printf("i am father process\n");
pthread_mutex_lock(mutex);
memcpy(buf,"world",6);
sleep(3);
printf("parent buf is :%s\n", buf);
pthread_mutex_unlock(mutex);
}
pthread_mutexattr_destroy(&mutexattr);
pthread_mutex_destroy(mutex);
munmap(buf,100);//解除映射
shm_unlink(shm);//消除共享内存
shm_unlink(shm1);
}
将互斥量的属性设置成线程共享的属性,就可以同步多进程了。
线程的分离属性
分离属性:通知当前系统该线程结束时,其所属资源可以回收,没有被分离的则会保留它的虚拟内存,包括堆栈和其他系统资源。即僵尸进程。创建线程默认是非分离的。
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
-设置线程的分离属性
PTHREAD_CREATE_DETACHED 分离的
PTHREAD_CREATE_JOINABLE 非分离的
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
-获取线程的分离属性
设置线程分离属性的步骤
定义线程属性变量pthread_attr_t attr
初始化attr,pthread_attr_init(&attr)
设置线程为分离或非分离
线程创建pthread(&tid ,&attr ,thread_fun,NULL).
#include "stdio.h"
#include "pthread.h"
#include "stdlib.h"
#include "signal.h"
#include "string.h"
#include "unistd.h"
void *thread_fun1(void *arg)
{
printf("i am new thread1\n");
return(void *)1;
}
void *thread_fun2(void *arg)
{
printf("i am new thread2\n");
return(void *)2;
}
int main()
{
pthread_t tid1,tid2;
int err;
pthread_attr_t attr; //1.define
pthread_attr_init(&attr); //2.init
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); //setdetcath
err=pthread_create(&tid1,&attr,thread_fun1,NULL); //分离pthread1
err=pthread_create(&tid2,NULL,thread_fun1,NULL);
err=pthread_join(tid1,NULL);
if(!err)
printf("join thread1 success\n"); //0是成功,非0是失败
else
printf("join thread1 failed\n");
err=pthread_join(tid2,NULL);
if(!err)
printf("join thread2 success\n");
else
printf("join thread2 failed\n");
}
可见分离后不能连接了。
参数若为JOINABLE 都能连接成功
线程的栈属性
对于线程来说,虚拟地址空间的大小是固定的,线程中只有一个栈。但对线程来说,通有的虚拟地址被所有的线程共享。如果应用程序使用太多的线程,导致线程栈累计超过可用的虚拟地址空间,这个适合就要减少线程默认的栈大小。另外,如果线程分配了大量的自动变量或线程的栈帧太深,那么这个时候需要的栈要比默认的大。
如果虚拟地址用完了,可以使用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)
-获取属性
stackaddr是栈的内存单元最低地址,但不一定是栈的开始。对于一些处理器,栈的地址是从高往低的,那么stackaddr是栈的结尾。
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstacksize(pthread_attr_t *attr, size_t stacksize);
线程属性guardsize控制着线程末尾以后用以避免栈溢出的扩展内存的大小,这个属性默认是PAGESIZE个字节。
int pthread_attr_setguardsize(pthread_attr_t *attr, siez_t guardsize);
int pthread_attr_getguardsize(pthread_attr_t *attr, size)t *guaradsize)
#include "stdio.h"
#include "pthread.h"
#include "stdlib.h"
#include "signal.h"
#include "string.h"
#include "unistd.h"
#include "limits.h"
pthread_attr_t attr;
void *thread_fun1(void *arg)
{
size_t stacksize;
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
pthread_attr_getstacksize(&attr, &stacksize);
printf("new thread stack size is %d\n",stacksize);
pthread_attr_setstacksize(&attr, 16389);
pthread_attr_getstacksize(&attr, &stacksize);
printf("new thread stack size is %d\n",stacksize);
#endif
return (void *)1;
}
int main()
{
pthread_t tid1;
int err;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);//可连接
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);//线程属性设定为最小堆栈 屏蔽掉这句就会输出默认的
#endif
err=pthread_create(&tid1,&attr,thread_fun1,NULL);
pthread_join(tid1,NULL);
return 0;
}