APUE线程控制

pag314

int pthread_attr_init( pthread_attr_t*attr )  //初始化pthread_attr_t结构
int pthread_attr_destroy(pthread_attr_t *attr )//去初始化;释放动态内存;用无效的值初始化属性对象(被误用会导致pthread_create函数返回错误)

分离线程:线程函数完成后,OS将其资源自动收回
不分离线程:如果不调用pthread_join,或者不结束整个进程,OS不会回收其资源

int pthread_attr_getdetachstate( constpthread_attr_t *restrict attr, int *detachstate ) //获取当前线程属性
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate )  //设置线程属性:
PTHREAD_CREATE_DETACHED 分离状态启动线程
PTHREAD_CREATE_JOINABLE  正常状态启动线程

int pthread_attr_getstack( constpthread_attr_t *restrict attr, void **restrict stackaddr, size_t*restrict stacksize ); //获取线程栈属性
int pthread_attr_setstack( constpthread_attr_t *attr, void *stackaddr, size_t *stacksize );//设置线程栈位置
对进程来说,虚拟地址空间的大小是固定的,进程中只有一个栈
如果用完了线程栈的虚拟地址空间,可以使用malloc或者mmap来为其他栈分配空间,并用pthread_attr_setstack函数改变新建线程的栈位置。

int pthread_attr_getstacksize( constpthread_attr_t *restrict attr, size_t *restrict stacksize );//获取栈大小
int pthread_attr_setstacksize( constpthread_attr_t *attr, size_t stacksize ); //设置栈大小

int pthread_attr_getguardsize( constpthread_attr_t *restrict attr, size_t *restrict guardsize );//获取线程栈末尾之后用以避免栈溢出的扩展内存的大小
int pthread_attr_setguardsize( constpthread_attr_t *attr, size_t stacksize );//设置线程栈末尾之后用以避免栈溢出的扩展内存的大小
guardsize控制线程栈末尾之后用以避免栈溢出的扩展内存的大小。属性默认为PAGESIZE个字节。
guardsize为0时不会提供警戒缓冲区
如果对线程属性stackaddr做的修改,系统会使警戒栈缓冲区机制无效,等同为guardsize为0

并发度控制着用户级线程可以映射的内核线程或进程的数目。
int pthread_ getconcurrency( void );//返回当前并发度
int pthread_ setconcurrency( int level);//设置系统并发度

pag318

int pthread_mutexattr_init(pthread_mutexattr_t *attr );
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr );

在进程中,默认行为时多个线程可以访问同一个同步对象。在这种情况下 进程共享互斥量属性需设置为PTHREAD_PROCESS_PRIVATE
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr, int *restrict pshared);//获取进程共享属性
int pthread_mutexattr_setpshared(const pthread_mutexattr_t *attr, int pshared );//设置进程共享属性


互斥量类型属性
1、PTHREAD_MUTEX_NORMAL  标准,不做错误检测、死锁检测
2、PTHREAD_MUTEX_RECURSIVE    允许同一线程在互斥量解锁之前对该互斥量进行多次加锁
3、PTHREAD_MUTEX_ERRORCHECK  提供错误检查
4、PTHREAD_MUTEX_DEFAULT  请求默认语义(linux映射到NORMAL)
int pthread_mutexattr_gettype( constpthread_mutexattr_t *restrict attr, int *restrict type);//获取互斥量类型属性
int pthread_mutexattr_settype( constpthread_mutexattr_t *attr, int type );//设置互斥量类型属性

互斥量用于保护与条件变量关联的条件时,在阻塞线程 之前,pthread_cond_wait和pthread_cond_timedwait函数 释放与条件相关的互斥量,这就 允许其他线程获取互斥量、改变条件、释放互斥量并向条件变量发送信号。(因此使用递归互斥量时要特别小心,wait,timedwait只解锁一层)

int pthread_rwlockattr_init(pthread_ rwlockattr_t *attr );
int pthread_ rwlockattr_destroy(pthread_ rwlockattr_t *attr );
int pthread_ rwlockattr_getpshared( constpthread_ rwlockattr_t *restrict attr,int *restrict pshared );
int pthread_ rwlockattr_setpshared( constpthread_ rwlockattr_t *attr, intpshared );

int pthread_condattr_init(pthread_ condattr_t *attr );
int pthread_ condattr_destroy(pthread_ condattr_t *attr );
int pthread_ cond attr_getpshared(const pthread_ condattr_t *restrictattr, int *restrict pshared );
int pthread_ condattr_setpshared(const pthread_ condattr_t *attr, intpshared );

如果一个函数对多个线程来说时可重入的,则说这个函数是线程安全的。
如果函数对异步信号处理程序的重入是安全的,那么就可以说函数时异步信号安全的。

FILE对象相关锁操作
int ftrylockfile( FILE *fp );
void flockfile( FILE *fp );
void funlockfile( FILE *fp );

进程中的所有线程都可以访问进程的整个地址空间。除了使用寄存器以外,线程没有办法阻止其他线程访问他的数据,线程私有数据也不例外。

在分配线程私有数据之前,需要创建一个与该数据关联的键,这个键将用于获取对线程私有数据的访问权。
int pthread_key_create( pthread_key_t*keyp, void (*destructor)(void *) );//创建一个键和与键关联的析构函数
int pthread_key_delete( pthread_key_t*key ); //删除键(不会激活与键相关联的析构函数)

pthread_once_t initflag = PTHREAD_ONCE_INIT;//initflag必须时一个非本地变量(是全局或静态变量),必须初始化为PTHREAD_ONCE_INIT
int pthread_once( pthread_once_t*initflag, void (*initfn)(void) ); //保证初始化initfn只被调用一次。

void * pthread_getspecific(pthread_key_t key ); //获得线程私有数据地址
int pthread_setspecific( pthread_key_tkey, const void * value); //把键和线程私有数据关联起来

取消点:线程检查是否被取消并按照请求进行动作的一个位置
pthread_cancel调用并不等待线程终止,在默认情况下,线程在取消请求发出以后还是继续运行,直到线程到达某个取消点。
int pthread_setcancelstate( int state,int *oldstate);//修改可取消状态(PTHREAD_CANCEL_ENABLE、PTHREAD_CANCEL_DISABLE)
void pthread_testcancel( void );//自己添加取消点(如果某个取消请求处于未决状态,而且取消没有置为无效,那么线程就会被取消。但是如果取消设置被置为无效,此函数没有任何效果)( 取消点需要和 未决信号相结合才能取消一个进程)
int pthread_setcanceltype( int type,int *oldtype ); //修改取消类型(异步取消(可在任意时间取消),延迟取消(默认状态))

pag334
每个线程都有 自己的信号屏蔽字,但是 信号的处理是进程中所有线程共享的。
进程中的信号时递送到单个线程的
int pthread_sigmask( int how, constsigset_t *restrict set, sigset_t *restrict oset);//信号屏蔽(单线程中的sigprocmask)
int sigwait( const sigset_t *restrict set, int *restrict signop ); //等待信号发生
为了避免错误,线程在调用sigwait之前, 必须阻塞那些他正在等待的信号(sigsuspend一样)。sigwait会自动取消信号集的阻塞状态(和sigsuspend有所区别,sigwait是取消set中屏蔽的信号阻塞,而sigsuspend是需要在传入的信号屏蔽字sigmask中取消对相应信号的屏蔽,且sigsuspend需要和信号处理函数相配合),直到有新的信号被递送。在返回之前将恢复线程的信号屏蔽字。
为了防止信号中断线程,可以把信号加到每个线程的信号屏蔽字中,然后安排专用线程作信号处理
新建线程 继承了现有的信号屏蔽字(子进程也有继承)
int pthread_kill( pthread_t thread,int signo );// 发送信号到线程
闹钟定时器时进程资源,并且所有的线程共享相同的alarm,所以进程中的多个线程 不可能互不干扰

pag337
子进程通过继承整个地址空间的副本(内存是fork时就分配的,但是里面的内容是写时才复制),也从父进程那里继承了所有互斥量、读写锁和条件变量的状态。如果父进程包含多个线程、子进程在fork返回以后,如果紧接着不是马上调用exec的话,就需要清理锁状态。
int pthread_atfork(void(* prepare)( void ), void (*parent)( void ), void(*child)(void )
);// 清除锁状态建立fork处理程序
prepare fork处理程序在调用fork以后运行,childfork处理程序在fork调用返回到子进程之前运行,parentfork处理程序在fork调用返回给父进程前运行。

你可能感兴趣的:(APUE线程控制)