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线程就会自动退出。省去了给线程擦屁股的麻烦。
什么是堆,什么是栈,什么是堆栈?
堆是动态分配的内存;
栈又叫做堆栈,是受限的线性表;