您的位置:首页 > 编程语言

UNIX环境高级编程-第12章- 线程控制 - 一

2015-01-06 16:04 330 查看

 12.3 线程属性

在创建新的线程时,我们可以使用系统默认的属性,也可以自己指定线程的主要属性。我们可以指定 pthread_attr_t 结构修改线程的默认属性,并把这个属性与创建线程联系起来。下面先看下线程的主要属性:

/* 线程属性 */

/*
* 线程的主要属性:
* (1)detachstate 线程的分离状态属性;
* (2)guardsize 线程栈末尾的警戒缓冲区大小(字节数);
* (3)stackaddr 线程栈的最低地址;
* (4)stacksize 线程栈的大小(字节数);
*/
下面是初始化属性结构,调用函数 pthread_attr_init 初始化线程之后,其结构所包含的内容都是操作系统实现支持的线程所有属性的默认值。
/*
* 函数功能:初始化属性结构;
* 返回值:若成功则返回0,否则返回错误编码;
* 函数原型:
*/
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);//初始化;
int pthread_attr_destroy(pthread_attr_t *attr);//若是动态分配的内存空间,则在释放内存之前调用此函数;

       下面针对线程的主要属性进行分析

分离状态属性

        在前面介绍线程终止时,分析了与线程内存资源回收有关的分离状态函数pthread_detach ,该函数对线程的终止状态没有兴趣,只是回收终止线程的系统资源。我们可以通过 pthread_attr_t 结构修改线程分离状态属性detachstate,下面是关于对该属性操作的函数:

/*
* 函数功能:修改线程的分离状态属性;
* 返回值:若成功则返回0,否则返回错误编码;
* 函数原型:
*/
#include <pthread.h>
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);//获取当前线程的分离状态属性;
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);//设置当前线程的分离状态属性;
/*
* 说明:
* detachstate的值为以下两种:
* (1)PTHREAD_CREATE_DETACHED 以分离状态启动线程;
* (2)PTHREAD_CREATE_JOINABLE 正常启动线程;
*/

栈属性

           可以通过下面的操作函数来获取或者修改线程的栈属性。

/*
* 函数功能:获取或修改线程的栈属性;
* 返回值:若成功则返回0,否则返回错误编码;
* 函数原型:
*/
#include <pthread.h>
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);//修改线程栈信息;

int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);//获取栈大小的信息;
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);//设置栈大小;

int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize);
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);

        进程只有一个栈,其虚拟地址空间的大小是固定的,而对线程来说,同样大小虚拟地址空间必须被所有的线程栈共享。如果应用程序使用了太多的线程,致使线程栈的累计大小超过了可用的虚拟地址空间,这时需要减少线程的数量。如果用完了线程栈的虚拟地址空间,可以使用malloc或者mmap来为其他栈分配空间,并用pthread_attr_setstack 函数来改变线程栈位置。线程栈所占内存范围中可寻址的最低地址可以由stackaddr 参数指定。
        线程属性 guardsize 控制着线程栈末尾之后用以避免栈溢出的扩展内存的大小,这个属性默认为PAGESIZE 个字节。可以把guardsize 线程属性设置为0,从而不允许属性的这种特性行为发生:在这种情况下不会提供警戒缓冲区。同样地,如果对线程属性stackaddr做了修改,系统就会假设我们会自己管理栈,并使警戒栈缓冲区机制无效,等同于guardsize线程属性设置为0.

并发度

        并发度控制着用户级线程可以映射的内核线程或进程的数目,如果操作系统的实现在内核级的线程和用户级的线程之间保持一对一的映射,那么改变并发度并不会有什么效果,因为所有的线程都可能被调度到,但是如果操作系统的实现让用户级线程到内核级线程或进程之前的映射关系是多对一的话,那么在给定时间内增加可运行的用户级线程数,可能会改善性能。pthread_setconcurrency 函数可以用于提示系统,表明希望的并发度

/*
* 函数功能:获取线程并发度信息;
* 函数原型:
*/
#include <pthread.h>
int pthread_getconcurrency(void);//获取当前并发度;
int pthread_setconcurrency(int level);//设置并发度
/*
* 说明:
* 设置并发度只是提示系统,系统并不一定采取;
*/

测试程序:
#include <apue.h>
#include <pthread.h>

static int makethread(void *(*fn)(void *), void *arg);
static void *fun(void *arg);

int main(void)
{
int err;

err = makethread(fun, NULL);
if(err != 0)
err_quit("can't create thread: %s\n", strerror(err));
sleep(3);
}

static int makethread(void *(*fn)(void *), void *arg)
{
pthread_t tid;
pthread_attr_t attr;
int err;

err = pthread_attr_init(&attr);
if(err != 0)
return(err);
err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//创建以分离状态启动的线程
if(0 == err)
err = pthread_create(&tid, &attr, fn, arg);
pthread_attr_destroy(&attr);
return(err);
}

static void *fun(void *arg)
{
pthread_t tid;
pthread_attr_t attr;
size_t size;
int state;
void *addr;

tid = pthread_self();
pthread_getattr_np(tid, &attr);
pthread_attr_getdetachstate(&attr, &state);
printf("detachstate = ");
if(state == PTHREAD_CREATE_DETACHED)
printf("PTHREAD_CREATE_DETACHED\n");
else if(state == PTHREAD_CREATE_JOINABLE)
printf("PTHREAD_CREATE_JOINABLE\n");

pthread_attr_getstack(&attr, &addr, &size);
printf("stack address = %p\n", addr);
printf("stack size = 0x%x bytes\n", size);
pthread_attr_getguardsize(&attr, &size);
printf("guard size = %d bytes\n",size);

return((void *)0);
}

输出结果:
[root@localhost 11]# gcc 11-8.c -lpthread
[root@localhost 11]# ./a.out
detachstate = PTHREAD_CREATE_DETACHED
stack address = 0xb75e8000
stack size = 0xa01000 bytes
guard size = 4096 bytes
[root@localhost 11]#


12.4 同步属性   

在前面章节介绍的线程同步都是默认属性,这里将要介绍在线程同步的互斥量、读写锁和条件变量的属性,可以指定一些属性来避免死锁等情况。

互斥量属性

        互斥量属性可以用 pthread_mutexattr_t 数据结构来进行操作,属性的初始化操作如下:

/* 同步属性 */

/* 互斥量属性 */
/*
* 函数功能:初始化互斥量属性;
* 返回值:若成功则返回0,否则返回错误编码;
* 函数原型:
*/
#include <pthread.h>
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
/*
* 说明:
* pthread_mutexattr_init函数用默认的互斥量属性初始化pthread_mutexattr_t结构;
* 两个属性是进程共享属性和类型属性;
*/

/*
* 函数功能:获取或修改进程共享属性;
* 返回值:若成功则返回0,否则返回错误编码;
* 函数原型:
*/
#include <pthread.h>
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared);//获取互斥量的进程共享属性
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);//设置互斥量的进程共享属性
/*
* 说明:
* 进程共享互斥量属性设置为PTHREAD_PROCESS_PRIVATE时,允许pthread线程库提供更加有效的互斥量实现,这在多线程应用程序中是默认的;
* 在多个进程共享多个互斥量的情况下,pthread线程库可以限制开销较大的互斥量实现;
*/

/*
* 函数功能:获取或修改类型属性;
* 返回值:若成功则返回0,否则返回错误编码;
* 函数原型:
*/
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type);//获取互斥量的类型属性
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);//修改互斥量的类型属性

互斥量类型用途没有解锁时再次加锁不占用是解锁在已解锁是解锁
PTHREAD_MUTEX_NORMAL标准类型,不做任何检查死锁未定义未定义
PTHREAD_MUTEX_ERRORCHECK进程错误检查返回错误返回错误返回错误
PTHREAD_MUTEX_RECURSIVE避免死锁允许返回错误返回错误
PTHREAD_MUTEX_DEFFAULT请求默认语义未定义未定义未定义

读写锁属性

读写锁属性只有进程共享属性,其属性操作如下:
/* 读写锁属性 */
/*
* 函数功能:初始化读写锁属性;
* 返回值:若成功则返回0,否则返回错误编码;
* 函数原型:
*/
#include <pthread.h>
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);
/*
* 说明:
* 读写锁的唯一属性就是进程共享,该属性与互斥量的进程共享相同;
*/

/*
* 函数功能:获取或修改读写锁的进程共享属性;
* 返回值:若成功则返回0,否则返货错误编码;
* 函数原型:
*/
int pthread_rwlock_getpshared(const pthread_rwlockattr_t *attr, int *pshared);
int pthread_rwlock_setpshared(pthread_rwlockattr_t *attr, int pshared);


条件变量属性

条件变量也只有进程共享属性,其操作如下:
/* 条件变量属性 */
/*
* 函数功能:初始化条件变量属性;
* 返回值:若成功则返回0,否则返回错误编码;
* 函数原型:
*/
#include <pthread.h>
int pthread_condattr_init(pthread_condattr_t *attr);
int pthread_condattr_destroy(pthread_condattr_t *attr);
/*
* 函数功能:获取或修改进程共享属性;
* 返回值:若成功则返回0,否则返回错误编码;
* 函数原型:
*/
#include <pthread.h>
int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *pshared);
int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared);

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: