linux线程通信(四)线程的属性

线程的高级属性

一次性初始化

有些时器需要且只能执行一次,比如互斥量初始化。如果库函数中有互斥量,使用一次初始会比较容易
一次性初始化 pthread_once_t变量,这个变量要用宏PTHREAD_ONCE_INIT初始化,然后创建一个与控制变量相关的初始化函数

  1. pthread_once_t once_control = PTHREAD_ONCE_INIT;
  2. void init-routine()
    {
    初始化互斥量
    初始化读写锁

    }
  3. 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类型的结构表示
linux线程通信(四)线程的属性_第1张图片
并不是所有系统都支持线程的这些属性,需要检查当前系统是否支持你设置的属性。
还有一些属性不包含在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 得知系统是否支持

linux线程通信(四)线程的属性_第2张图片
设置互斥量的类型属性

  • int othreaed_mutex_gettype(const pthread_mutexattr_t *restrict attr, int *restrict type);
  • int othreaed_mutex_settype(const pthread_mutexattr_t * attr, int *type);

例:
linux线程通信(四)线程的属性_第3张图片

#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);
    -获取线程的分离属性

设置线程分离属性的步骤

  1. 定义线程属性变量pthread_attr_t attr
  2. 初始化attr,pthread_attr_init(&attr)
  3. 设置线程为分离或非分离
  4. 线程创建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;

}

在这里插入图片描述

你可能感兴趣的:(linux线程通信(四)线程的属性)