天天看点

《unix高级环境编程》线程控制——线程属性

       在创建新的线程时,我们可以使用系统默认的属性,也可以自己指定线程的主要属性。我们可以指定 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);
}
           

输出结果:

detachstate = PTHREAD_CREATE_DETACHED
stack address = 0xb6dab000
stack size = 0x801000 bytes
guard size = 4096 bytes
           

参考资料:

《UNIX高级环境编程》

继续阅读