Chinaunix首页 | 论坛 | 博客
  • 博客访问: 66612
  • 博文数量: 20
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 11
  • 用 户 组: 普通用户
  • 注册时间: 2019-01-15 20:17
文章分类
文章存档

2019年(20)

我的朋友

分类: 嵌入式

2019-01-15 20:54:53

一、线程有哪些属性
    线程的属性用pthread_attr_t类型的结构表示,在创建线程的时候可以不用传入NULL,而是传入一个pthread_attr_t结构,由用户自己来配置线程
    的属性。pthread_attr_t类型对应用程序是不透明的,也就是说应用程序不需要了解有关属性对象内部结构的任何细节,因而可以增加程序的可
    移植性

    线程属性
    名称                         描述
    detachstate              线程的分离状态
    guardsize                线程栈末尾的警戒区域大小(字节数)
    stacksize                 线程栈的最低地址
    stacksize                 线程栈的大小(字节数)

     并不是所有的系统都支持线程的这些属性,因此你需要检查当前系统是否支持你设置的属性
     当然还有一些属性不包含在pthread_attr_t结构中,例如:线程的可取消状态、取消类型、并发度

二、线程属性初始化和销毁
    pthread_attr_t结构在使用之前需要初始化,使用完之后需要销毁
    1、线程属性初始化
     int pthread_attr_init(pthread_attr_t *attr);
    2、线程属性销毁
     int pthread_attr_destroy(pthread_attr_t *attr);
    如果在调用pthread_attr_init初始化属性的时候分配了内存空间,那么pthread_attr_destroy将释放内存空间。除此之外,pthread_atty_destroy
    还会用无效的值初始化pthread_attr_t对象,因此如果该属性对象被误用,会导致创建线程失败

三、线程的分离属性
    1、分离属性的概念
        分离一个正在运行的线程并不影响它,仅仅是通知当前系统该线程结束时,其所属的资源可以回收。一个没有被分离的线程在终止时会保留
        它的虚拟内存,包括他们的堆栈和其他系统资源,有时这种线程被称为“僵尸线程”。创建线程时默认是非分离的
        如果线程具有分离属性,线程终止时会被立刻回收,回收将释放掉所有在线程终止时未释放的系统资源和进程资源,包括保存线程返回值的
        内存空间、堆栈、保存寄存器的内存空间等。
    2、分离属性的使用方法
        如果在创建线程的时候就直到不需要了解线程的终止状态,那么可以修改pthread_attr_t结构体的detachstate属性,让线程以分离状态启动。
        可以使用pthread_attr_setdetachstate函数来设置线程的分离状态属性。线程的分离属性有两种合法值:
            PTHREAD_CREATE_DETACHED分离的
            PTHREAD_CREATE_JOINABLE 非分离的,可连接的

         int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
         int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
        使用pthread_attr_getdetachstate可以获得线程的分离状态属性

        设置线程分离属性的步骤
        1)、定义线程属性变量pthread_attr_t attr
        2)、初始化attr,pthread_attr_init(&attr)
        3)、设置线程为分离或非分离 pthread_attr_setdetachstate(&attr, detachstate)
        4)、创建线程pthread_create(&tid, &attr, thread_fun,  NULL)
        所有的系统都会支持线程的分离状态属性,

四、线程栈属性
    1、线程的栈大小
        对于进程来说,虚拟地址空间的大小是固定的,进程中只有一个栈,因此它的大小通常不是问题。但对线程来说,同样的虚拟地址被所有的
        线程共享。如果应用程序使用了太多的线程,致使线程栈累计超过可用的虚拟地址空间,这个时候就需要减少线程默认的栈大小。另外,如
        果线程分配了大量的自动变量或者线程的栈帧太深,那么这个时候需要的栈要比默认的大。

        如果用完了虚拟地址空间,可以使用malloc或者mmap来为其他栈分配空间,并修改栈的位置。
        1)、修改栈属性
         int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
        2)、获取栈属性
         int pthread_attr_getstack(pthread_attr_t *attr, void **stackaddr, size_t *stacksize);
        参数stackaddr是栈的内存单元最低地址,参数stacksize是栈的大小。你要注意stackaddr并不一定是栈的开始,对于一些处理器,栈的地址是
        从高往低的,那么这是stackaddr是栈的结尾。


        当然也可以单独获取或者修改栈的大小,而不去修改栈的地址。对于栈大小设置,不能小于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);
        对于栈大小的设置,在创建线程之后,还可以修改。

        对于遵循POSIX标准的系统来说,不一定要支持线程的栈属性,因此你需要检查
        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函数检查系统对线程栈属性的支持
    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);

五、手册
PTHREAD_ATTR_INIT(3)       Linux Programmer’s Manual      PTHREAD_ATTR_INIT(3)
NAME
       pthread_attr_init, pthread_attr_destroy - initialize and destroy thread attributes object
        //初始化或者销毁线程的属性

SYNOPSIS
       #include
        //头文件

       int pthread_attr_init(pthread_attr_t *attr);
       int pthread_attr_destroy(pthread_attr_t *attr);

       Compile and link with -pthread.
        //编译连接线程库

DESCRIPTION
       The pthread_attr_init() function initializes the thread attributes object pointed to by attr with default attribute val-
       ues.  After this call, individual attributes of the object can be set using various related functions (listed under  SEE
       ALSO), and then the object can be used in one or more pthread_create(3) calls that create threads.
        //pthread_attr_init()初始化属性,当它成功返回之后,这个属性的值就是有效的,可以被使用在多个线程的创建中

       Calling  pthread_attr_init() on a thread attributes object that has already been initialized results in undefined behav-
       ior.
        //如果一个线程的属性已经被初始化了,那么多次调用pthread_attr_init()导致未知的结果

       When a thread attributes object is no longer required, it should be destroyed using the pthread_attr_destroy() function.
       Destroying a thread attributes object has no effect on threads that were created using that object.
        //当一个线程属性不在需要的时候,应该被销毁。销毁一个属性,对于已经创建好的线程没有任何影响
    
       Once a thread attributes object has been destroyed, it can be reinitialized using pthread_attr_init().  Any other use of
       a destroyed thread attributes object has undefined results.
        //当一个线程属性被销毁以后,可以重新被初始化

RETURN VALUE
       On success, these functions return 0; on error, they return a non-zero error number.
        //成功返回0,失败返回错误码

ERRORS
       POSIX.1-2001 documents an ENOMEM error for pthread_attr_init(); on Linux these functions always  succeed  (but  portable
       and future-proof applications should nevertheless handle a possible error return).
     


PTHREAD_ATTR_SETDETACHSTATELinux Programmer’s MaPTHREAD_ATTR_SETDETACHSTATE(3)


NAME
       pthread_attr_setdetachstate, pthread_attr_getdetachstate - set/get detach state attribute in thread attributes object
        //设置或者得到线程的分离属性

SYNOPSIS
       #include
        //头文件

       int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
       int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);

       Compile and link with -pthread.
        //编译连接线程库

DESCRIPTION
       The  pthread_attr_setdetachstate()  function sets the detach state attribute of the thread attributes object referred to
       by thread to the value specified in detachstate.  The detach state attribute determines whether a thread  created  using
       the thread attributes object attr will be created in a joinable or a detached state.
        //pthread_attr_setdetachstate()设置线程的分离属性,分离属性决定了线程是否可以被连接

       The following values may be specified in detachstate:
        //线程的分离属性有以下值

       PTHREAD_CREATE_DETACHED
              Threads that are created using attr will be created in a detached state.
                //创建一个可以分离的线程

       PTHREAD_CREATE_JOINABLE
              Threads that are created using attr will be created in a joinable state.
                //创造一个不可分离的线程

       The  default  setting  of  the  detach  state  attribute in a newly initialized thread attributes object is PTHREAD_CRE-
       ATE_JOINABLE.
        //默认的线程分离属性是非分离的

       The pthread_attr_getdetachstate() returns the detach state attribute of the thread attributes object attr in the  buffer
       pointed to by detachstate.
        //pthread_attr_getdetachstate() 获取线程的分离属性

RETURN VALUE
       On success, these functions return 0; on error, they return a non-zero error number.
        //成功返回0,失败返回错误码

ERRORS
       pthread_attr_setdetachstate(3) can fail with the following error:
        //pthread_attr_setdetachstate() 会有以下的失败情况

       EINVAL An invalid value was specified in detachstate.
        //分离属性的值是无效的

 
 PTHREAD_ATTR_SETSTACK(3)   Linux Programmer’s Manual  PTHREAD_ATTR_SETSTACK(3)
NAME
       pthread_attr_setstack, pthread_attr_getstack - set/get stack attributes in thread attributes object
        //得到或者设置线程的栈属性

SYNOPSIS
       #include
        //头文件

       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);

       Compile and link with -pthread.
        //编译连接线程库

       Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
       pthread_attr_getstack(), pthread_attr_setstack(): _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600

DESCRIPTION
       The  pthread_attr_setstack()  function  sets the stack address and stack size attributes of the thread attributes object
       referred to by attr to the values specified in stackaddr and stacksize,  respectively.   These  attributes  specify  the
       location  and size of the stack that should be used by a thread that is created using the thread attributes object attr.
        //pthread_attr_setstack()设置栈的地址和栈的大小,设置好的栈属性会在创建线程的时候被使用

       stackaddr should point to the lowest addressable byte of a buffer of stacksize bytes that was allocated by  the  caller.
       The pages of the allocated buffer should be both readable and writable.
        //栈地址是栈的最低地址

       The pthread_attr_getstack() function returns the stack address and stack size attributes of the thread attributes object
       referred to by attr in the buffers pointed to by stackaddr and stacksize, respectively.
        //pthread_attr_getstack()返回栈的地址和大小

RETURN VALUE
       On success, these functions return 0; on error, they return a non-zero error number.
        //成功返回0,失败返回错误码

ERRORS
       pthread_attr_setstacksize() can fail with the following error:
        //pthread_attr_setstack()会在可能返回下列错误码

       EINVAL stackaddr is less than PTHREAD_STACK_MIN (16384) bytes.  On some systems, this error may also occur if  stackaddr
              or stackaddr + stacksize is not suitably aligned.
        //栈的地址小于PTHREAD_STACK_MIN,在某些系统中如果栈地址或者栈地址+栈大小没有对齐,那么也会失败

       POSIX.1-2001  also documents an EACCES error if the stack area described by stackaddr and stacksize is not both readable
       and writable by the caller.


PTHREAD_ATTR_SETSTACKSIZE(3Linux Programmer’s ManuPTHREAD_ATTR_SETSTACKSIZE(3)
NAME
       pthread_attr_setstacksize, pthread_attr_getstacksize - set/get stack size attribute in thread attributes object
        //设置或者获取栈的大小

SYNOPSIS
       #include
        //头文件
        
       int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
       int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);

       Compile and link with -pthread.
        //编译连接线程库

DESCRIPTION
       The  pthread_attr_setstacksize()  function  sets the stack size attribute of the thread attributes object referred to by
       attr to the value specified in stacksize.
        //pthread_attr_setstacksize()设置栈的大小

       The stack size attribute determines the minimum size (in bytes) that will be allocated for  threads  created  using  the
       thread attributes object attr.
        //栈的大小决定了线程的最小栈

       The pthread_attr_getstacksize() function returns the stack size attribute of the thread attributes object referred to by
       attr in the buffer pointed to by stacksize.
        //pthread_attr_getstacksize()获得栈的大小

RETURN VALUE
       On success, these functions return 0; on error, they return a non-zero error number.
        //成功返回0,失败返回错误码

ERRORS
       pthread_attr_setstacksize() can fail with the following error:
        //pthread_attr_setstacksize()可能有以下错误

       EINVAL The stack size is less than PTHREAD_STACK_MIN (16384) bytes.
                    //栈的大小小于PTHREAD_STACK_MIN 

       On some systems, pthread_attr_setstacksize() can fail with the error EINVAL if stacksize is not a multiple of the system
       page size.
        //如果栈的大小不是pagesize的倍数,那么也有可能会失败


六、实例
    1、线程分离属性
        程序框图

    源代码

点击(此处)折叠或打开

  1. /*DATE:            2015-4-15
  2.  *AUTHOR:        DDDDD
  3.  *DESCRIPTION:    设置线程到分离属性
  4.  *如果在创建线程的时候就直到不需要了解线程的终止状态,那么可以修改pthread_attr_t结构体的detachstate属性,
  5.  *让线程以分离状态启动。可以使用pthread_attr_setdetachstate函数来设置线程的分离状态属性。线程的分离属性有
  6.  *两种合法值:
  7.  *    PTHREAD_CREATE_DETACHED分离的
  8.  *    PTHREAD_CREATE_JOINABLE 非分离的,可连接的
  9.  *    int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
  10.  * int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
  11.  * 使用pthread_attr_getdetachstate可以获得线程的分离状态属性
  12.  *
  13.  * 设置线程分离属性的步骤
  14.  * 1、定义线程属性变量pthread_attr_t attr
  15.  * 2、初始化attr,pthread_attr_init(&attr)
  16.  * 3、设置线程为分离或非分离 pthread_attr_setdetachstate(&attr, detachstate)
  17.  * 4、创建线程pthread_create(&tid, &attr, thread_fun, NULL)
  18.  * 所有的系统都会支持线程的分离状态属性
  19.  */

  20. #include "apue.h"


  21. void *thread_fun1(void *arg)
  22. {
  23.     
  24.     printf("I'm new thread 1\n");

  25.     return (void *)1;
  26. }

  27. void *thread_fun2(void *arg)
  28. {
  29.     printf("I'm new thread 2\n");

  30.     return (void *)2;
  31. }

  32. int main()
  33. {
  34.     pthread_t tid1, tid2;
  35.     int err;

  36.     //定义属性变量
  37.     pthread_attr_t attr;
  38.     //初始化属性
  39.     pthread_attr_init(&attr);
  40.     //设置分离状态属性,置为已分离
  41.     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  42.     
  43.     err = pthread_create(&tid1, &attr, thread_fun1, NULL);
  44.     if(err)
  45.     {
  46.         printf("create new thread 1 failed\n");
  47.         return;
  48.     }
  49.     
  50.     err = pthread_create(&tid2, NULL, thread_fun2, NULL);
  51.     if(err)
  52.     {
  53.         printf("create new thread 2 failed\n");
  54.         return;
  55.     }

  56.     //连接线程1
  57.     err = pthread_join(tid1, NULL);
  58.     if(!err)
  59.         printf("join thread 1 success\n");
  60.     else
  61.         printf("join thread 1 failed\n");
  62.     //连接线程2
  63.     err = pthread_join(tid2, NULL);
  64.     if(!err)
  65.         printf("join thread 2 success\n");
  66.     else
  67.         printf("join thread 2 failed\n");

  68.     //销毁attr
  69.     pthread_attr_destroy(&attr);


  70.     return 0;
  71. }

    2、线程栈属性
        程序框架

        源代码

点击(此处)折叠或打开

  1. /*DATE:            2015-4-15
  2.  *AUTHOR:        DDDDD
  3.  *DESCRIPTION:    设置线程到分离属性
  4.  *    修改栈属性
  5.  *    int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
  6.  *    获取栈属性
  7.  *    int pthread_attr_getstack(pthread_attr_t *attr, void **stackaddr, size_t *stacksize);
  8.  *    参数stackaddr是栈的内存单元最低地址,参数stacksize是栈的大小。你要注意stackaddr并不一定是栈的开始,对于一些处理器,栈的地址是从高往低的,那么这是stackaddr是栈的结尾。
  9.  *
  10.  *    当然也可以单独获取或者修改栈的大小,而不去修改栈的地址。对于栈大小设置,不能小于PTHREAD_STACK_MIN
  11.  * int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
  12.  * int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);
  13.  * 对于栈大小的设置,在创建线程之后,还可以修改。
  14.  */

  15. #include "apue.h"

  16. pthread_attr_t attr;

  17. void *thread_fun(void *arg)
  18. {
  19.     size_t stacksize;
  20. #ifdef _POSIX_THREAD_ATTR_STACKSIZE
  21.     pthread_attr_getstacksize(&attr, &stacksize);
  22.     printf("new thread stack size is %d\n", stacksize);
  23.     pthread_attr_setstacksize(&attr, 1638);
  24.     pthread_attr_getstacksize(&attr, &stacksize);
  25.     printf("new thread stack size is %d\n", stacksize);
  26. #endif

  27.     
  28.     return (void *)1;
  29. }

  30. int main()
  31. {
  32.     pthread_t tid;
  33.     int err;

  34.     pthread_attr_init(&attr);
  35.     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

  36. #ifdef _POSIX_THREAD_ATTR_STACKSIZE
  37. //    pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
  38. #endif
  39.     
  40.     err = pthread_create(&tid, &attr, thread_fun, NULL);
  41.     if(err)
  42.     {
  43.         printf("create new thread failed\n");
  44.         return;
  45.     }
  46.     

  47.     pthread_join(tid, NULL);
  48.     return 0;
  49. }
阅读(1023) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~