关于pthread.h的属性及一点展开

pthread.h 参数attr
一些变量的定义:
 #include <sys/types.h>
    pthread_mutex_t:Used for mutexes.
    pthread_t:Used to identify a thread,线程的句柄是pthread_t类型, 该类型不能作为整数处理, 而是一个结构.

线程基础:头文件: <pthread.h>
    线程操作包括线程创建,终止,同步(联接,阻塞),调度,数据管理和流程交互。
    线程不维护已创建线程的列表,也不知道创建该线程的线程。
    进程内的所有线程共享相同的地址空间。
    同一进程中的线程共享:
        进程指令
        大多数数据
        打开文件(描述符)
        信号和信号处理程序
        当前工作目录
        用户和组ID
    每个线程都有一个唯一的:
        线程ID
        寄存器集,堆栈指针
        线程的堆栈
        信号屏蔽
        优先级别
        返回值:errno
        如果确定,pthread函数将返回“ 0”。
优点:
    (1) 提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线程,可以避免这种尴尬的情况。

    (2) 使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。

    (3)改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。
操作:
    线程创建:int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(start_rtn)(void), void *restrict arg);
        成功则返回0,否则返回出错编号
        tidp指向的内存单元被设置为新创建线程的线程ID
        attr参数用于制定各种不同的线程属性
        arg: 函数的唯一无类型(void)指针参数, 如要传多个参数, 可以用结构封装.
        编译时注意加上-lpthread参数
        Restrict:
    只用于限定指针,表明本指针是访问一个数据对象的惟一且初始的方式.
    只用于修饰指针,功能是帮助编译器进行优化!值得注意的是,优化需要就事论事,经过分析:如果发现确实优化不了,就不优化了。不加restrict关键字修饰的指针,编译器一定不进行优化!
attr:
    如果使用默认线程属性,则设置为NULL。pthread_attr_t主要包括scope属性、detach属性、堆栈地址、堆栈大小、优先级。
    typedef struct
            {
                   int                       detachstate;     线程的分离状态
                   int                       schedpolicy;     线程调度策略
                   struct sched_param        schedparam;      线程的调度参数
                   int                       inheritsched;    线程的继承性
                   int                       scope;           线程的作用域
                   size_t                    guardsize;       线程栈末尾的警戒缓冲区大小
                   int                       stackaddr_set;
                   void *                    stackaddr;       线程栈的位置
                   size_t                    stacksize;       线程栈的大小
            }pthread_attr_t;

 

较为常用的是detach,及优先级设置。

  int pthread_attr_init(pthread_attr_t* attr) 对线程属性变量的初始化。 返回成功0,失败-1

__detachstate,表示新线程是否与进程中其他线程脱离同步, 如果设置为PTHREAD_CREATE_DETACHED 则新线程不能用pthread_join()来同步,且在退出时自行释放所占用的资源。
缺省为PTHREAD_CREATE_JOINABLE状态。这个属性也可以在线程创建并运行以后用pthread_detach()来设置,而一旦设置为PTHREAD_CREATE_DETACH状态(不论是创建时设置还是运行时设置)则不能再恢复到PTHREAD_CREATE_JOINABLE状态。

线程的分离状态决定一个线程以什么样的方式来终止自己。在默认情况下线程是非分离状态的,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join() 函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。分离线程没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。
通俗的说也就是:我们知道一般我们要等待(pthread_join)一个线程的结束,主要是想知道它的结束状态,否则等待一般是没有什么意义的!但是if有一些线程的终止态我们压根就不想知道,那么就可以使用“分离”属性,那么我 们就无须等待管理,只要线程自己结束了,自己释放资源;
 #include <pthread.h>
int pthread_attr_getdetachstate(const pthread_attr_t * attr, int * detachstate);获取分离状态
int pthread_attr_setdetachstate(pthread_attr_t * attr, int detachstate);设置分离状态

__schedpolicy,表示新线程的调度策略,主要包括:
SCHED_OTHER(正常、非实时)
SCHED_RR(实时、轮转法)
SCHED_FIFO(实时、先入先出)
缺省为SCHED_OTHER,后两种调度策略仅对超级用户有效。
int pthread_attr_getschedpolicy(const pthread_attr_t *, int * policy)
int pthread_attr_setschedpolicy(pthread_attr_*, int policy)
若成功返回0,若失败返回-1。

__schedparam,一个struct sched_param结构,目前仅有一个sched_priority整型变量表示线程的运行优先级。这个参数仅当调度策略为实时(即SCHED_RR或SCHED_FIFO)时才有效,并可以在运行时通过pthread_setschedparam()函数来改变,缺省为0。
函数pthread_attr_getschedparam 和pthread_attr_setschedparam分别用来设置和得到线程的调度参数。

 int pthread_attr_getschedparam(const pthread_attr_t *,struct sched_param *);
int pthread_attr_setschedparam(pthread_attr_t *,const struct sched_param *);
若成功返回0,若失败返回-1。
参数:
attr 线程变量属性
param sched_parm 结构体
struct sched_param
{
int sched_priority; // 参数的本质就是优先级
};

 此处的SCHED_FIFO是允许被高优先级抢占的!
> 也就是有高优先级的必须先运行
> SCHED_RR是设置一个时间片
> 当有SCHED_FIFO或SCHED_RR策赂的线程在一个条件变量
上等持或等持加锁同一个互斥量时,它们将以优先级顺序被唤
醒。即,如果一个低优先级的SCHED_FIFO线程和一个高优先
织的SCHED_FIFO线程都在等待锁相同的互斥且,则当互斥量
被解锁时,高优先级线程将总是被首先解除阻塞。

大的权值对应高的优先级!
系统支持的最大和最小的优先级值可以用函数:
sched_get_priority_max和sched_get_priority_min得到!
  #include <pthread.h>
int sched_get_priority_max( int policy );
 int sched_get_priority_min( int policy );

__scope,表示线程间竞争CPU的范围,也就是说线程优先级的有效范围。
函数pthread_attr_setscope和pthread_attr_getscope分别用来设置和得到线程的作用域。  
int    pthread_attr_getscope( const pthread_attr_t * attr, int * scope );
int pthread_attr_setscope( pthread_attr_t*, int scope );
attr 线程属性变量
scope 线程的作用域
若成功返回0,若失败返回-1。
作用域控制线程是否在进程内或在系统级上竞争资源,可能的值是
PTHREAD_SCOPE_PROCESS(进程内竞争资源)
PTHREAD_SCOPE_SYSTEM (系统级竞争资源)。


继承性的可能值是PTHREAD_INHERIT_SCHED(表示新现成将继承创建线程的调度策略和参数)和PTHREAD_EXPLICIT_SCHED(表示使用在schedpolicy和schedparam属性中显式设置的调度策略和参数)。
int pthread_attr_getinheritsched(const pthread_attr_t * attr,int *inheritsched);
int pthread_attr_setinheritsched(pthread_attr_t * attr,int inheritsched);

第1个是指向属性对象的指针,第2个是继承性或指向继承性的指针。继承性决定调度的参数是从创建的进程中继承还是使用在schedpolicy和schedparam属性中显式设置的调度信息。Pthreads不为inheritsched指定默认值,因此如果你关心线程的调度策略和参数,必须先设置该属性。
如果你需要显式的设置一个线程的调度策略或参数,那么你必须在设置之前将inheritsched属性设置为PTHREAD_EXPLICIT_SCHED.

默认是inherit继承父线程的。

线程的栈的地址和大小:
int pthread_attr_getstack(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_setstackaddr(pthread_attr_t *attr, void *stackaddr);

int pthread_attr_getstackaddr(pthread_attr_t *attr, void**stackaddr);

int pthread_attr_setstacksize(pthread_attr_t *attr, size_tstacksize);

int pthread_attr_getstacksize(pthread_attr_t *attr, size_t*stacksize);

栈溢出保护区大小

intpthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);

intpthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize);
默认4096B,即4K
为什么需要栈溢出保护区:?

属性                值                                结果
scope            PTHREAD_SCOPE_PROCESS            新线程与进程中的其他线程发生竞争。
detachstate        PTHREAD_CREATE_JOINABLE            线程退出后,保留完成状态和线程ID。
stackaddr        NULL                            新线程具有系统分配的栈地址。
stacksize        0                                新线程具有系统定义的栈大小。
priority        0                                新线程的优先级为0。
inheritsched    PTHREAD_EXPLICIT_SCHED            新线程不继承父线程调度优先级。
schedpolicy        SCHED_OTHER                        新线程对同步对象争用资源

相关函数:
    初始化属性:int pthread_attr_init(pthread_attr_t *tattr);
            #include <pthread.h>
            pthread_attr_t tattr;
            int ret;
            /* initialize an attribute to the default value */
            ret = pthread_attr_init(&tattr); 
    销毁属性:int pthread_attr_destroy(pthread_attr_t *tattr);
            pthread_attr_destroy(&tattr);

---------------------------------------------------------------------------

同一个进程下,各个线程之间的数据是共享的,数据的种类可以有很多种,比如标准数据、结构体、文件描述符等等,但是这里有个前提,这些能够被共享的数据,一定是主线程在创建 子线程时,向 子线程传递的数据(通过指针传递)。
关于Linux栈:
内核将栈分成四种:
进程栈
线程栈
内核栈
中断栈
线程栈
从 Linux 内核的角度来说,其实它并没有线程的概念。Linux 把所有线程都当做进程来实现,它将线程和进程不加区分的统一到了 task_struct 中。线程仅仅被视为一个与其他进程共享某些资源的进程,而是否共享地址空间几乎是进程和 Linux 中所谓线程的唯一区别。

而这里所要找到的打开文件描述符表,实际上就是files_struct 中的成员struct file * fd_array[NR_OPEN_DEFAULT]它是一个指针数组,数组每一个元素都是一个指向file类型的指针,可想而知,这些指针都会指向一个打开的文件,并且file这一数据结构就是用来描述一个打开的文件的,而我们所说的文件描述符,实际上就是这个指针数组的索引。这也是为什么文件描述符是非负整数。

关于pthread_join()
    *分离状态,不需要join;
    *非分离状态,如果不join的话,会导致资源未释放,整个内存耗费增大。
    *1.linux线程执行和windows不同,pthread有两种状态joinable状态和unjoinable状态,如果线程是joinable状态,当线程函数自己返回退出时或pthread_exit时都不会释放线程所占用堆栈和线程描述符(总计8K多)。只有当你调用了pthread_join之后这些资源才会被释放。若是unjoinable状态的线程,这些资源在线程函数退出时或pthread_exit时自动会被释放。
    2.unjoinable属性可以在pthread_create时指定,或在线程创建后在线程中pthread_detach自己, 如:pthread_detach(pthread_self()),将状态改为unjoinable状态,确保资源的释放。或者将线程置为 joinable,然后适时调用pthread_join.
    3.其实简单的说就是在线程函数头加上 pthread_detach(pthread_self())的话,线程状态改变,在函数尾部直接 pthread_exit线程就会自动退出。省去了给线程擦屁股的麻烦。    
什么是堆,什么是栈,什么是堆栈?
    堆是动态分配的内存;
    栈又叫做堆栈,是受限的线性表;
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值