首页 > 代码库 > APUE: 线程相关库函数
APUE: 线程相关库函数
线程有时称为轻权进程。
进程的所有信息对该进程的所有线程都是共享的。
每个线程有一个线程ID,线程ID只在它所属的进程环境中有效。
线程从进程继承的东西:
进程ID
地址空间
浮点环境
信号屏蔽字(不包括未决的信号集)
线程间共享的东西:
进程指令
大部分数据
信号处理程序和信号处理
当前工作目录
用户ID和组ID
线程间独立的东西:
线程ID
寄存器集合
栈
errno
信号掩码
优先级
所有线程函数返回类型为int的成功返回0,失败返回错误码,不设置errno。
线程编程需要链接库:
-lpthread
#####################################################
线程相关库函数
#####################################################
#include<pthread.h>
intpthread_create(
pthread_t*restrict thread,
//返回的线程ID
constpthread_attr_t *restrict attr,
//线程属性,NULL表示使用默认值
void*(*start_routine)(void*),
//线程启动函数,返回void*,只有一个参数void*。
void*restrict arg
//如果参数不止一个,把这些参数放入一个结构,地址传给arg。
);
创建线程,相当于fork;成功返回0,失败返回错误码,不设置errno。
初始线程是程序开始执行时创建的主线程,其它线程是该函数创建的;线程创建时不能保证哪个线程先运行。
pthread_tpthread_self(void);
一个线程取得自己的线程ID,相当于getpid。
返回调用线程的线程ID。
intpthread_equal(pthread_ttid1, pthread_t tid2);
线程ID是一个结构pthread_t,如果两个线程ID相等返回非0,否则返回0.
intpthread_join(
pthread_tthread, //等待终止的线程ID
void**value_ptr
//如果非空,存放等待终止的线程的返回值;如果为空只是等待指定线程终止。
);
等待线程结束,相当于waitpid。
调用线程是默认阻塞的,value_ptr用来存放退出状态,如果线程处于分离状态,函数返回EINVAL。
intpthread_detach(pthread_tthread);
将指定线程设置为分离状态。
分离状态的线程底层存储资源可以在线程终止时立即被收回。
voidpthread_exit(void*value_ptr);
终止一个线程,相当于exit
value_ptr参数用来设置退出码,用pthread_join函数可以访问这个退出吗。
任一线程调用exit系列函数或向线程发送默认动作是终止的信号都可以终止整个进程。
正常终止线程方法:
1.最后一个线程从其启动例程返回
2.最后一个线程调用pthread_exit库函数
异常终止线程方法:
1.最后一个线程对取消请求做出响应
intpthread_cancel(pthread_tthread);
请求取消同一进程中的其它线程,并不等待线程终止。
相当于abort。
voidpthread_cleanup_push(void(*routine)(void*),
//返回void*,参数也是void*。
void*arg
//第二个参数是用来指定清理函数的更过参数
);
线程在下列情况调用清理函数routine:
1.调用pthread_exit
2.调用pthread_cancel并响应
3.用非零参数调用pthread_cleanup_pop
清理函数通过这个函数入栈,先入栈的后执行。
相当于abexit。
voidpthread_cleanup_pop(intexecute);
用来删除上次push的清理函数,如果execute=0那么还会禁止调用清理函数。
#####################################################
线程属性相关库函数
#####################################################
#include<pthread.h>
intpthread_attr_init(pthread_attr_t*attr);
初始化线程属性对象的结构attr。
intpthread_attr_destory(pthread_attr_t*attr);
清理和回收初始化之后的线程属性结构attr。
线程分离状态属性detachstate:
intpthread_attr_getdetachstate(constpthread_attr_t *attr, int *detachstate);
把线程属性detachstate设置为下面值:
PTHREAD_CREATE_DETACHED:以分离状态启动线程
PTHREAD_CREATE_JOINABLE:正常启动线程
intpthread_attr_setdetachstate(pthread_attr_t*attr, int detachstate);
获取线程的属性detachstate值。
线程栈最低地址:
intpthread_attr_setstack(pthread_attr_t*attr, void *stackaddr, size_t stacksize);
可以同时管理stackaddr和stacksize。
intpthread_attr_getstack(pthread_attr_t*attr, void **stackaddr, size_t *stacksize);
读取stackaddr和stacksize。
线程栈的大小:
intpthread_attr_setstacksize(pthread_attr_t*attr, size_t stacksize);
设置stacksize。
intpthread_attr_getstacksize(pthread_attr_t*attr, size_t stacksize);
读取stacksize。
线程栈末尾的警戒缓冲区大小:
intpthread_attr_setguardsize(pthread_attr_t*attr, size_t guardsize);
guardsize=0表示不允许使用这种特征。
intpthread_attr_getguardsize(pthread_attr_t*attr, size_t guardsize);
取消选项:
intpthread_setcancelstate(intstate, int *oldstate);
调用线程取消函数并不等待线程终止,而是到达取消点就取消。
将取消状态设置为state,原来的放在oldstate。
state:
PTHREAD_CANCEL_ENABLE(线程启动时的默认取消状态)
PTHREAD_CANCEL_DISABLE:调用取消函数处于未决状态,当恢复为enable时在下一个取消点作用。
intpthread_setcanceltype(inttype, int *oldtype);
将取消类型设置为type,将原来的放在oldtype。
type:
PTHREAD_CANCEL_DEFERRED:延时取消:到取消点才取消(默认)
PTHREAD_CANCEL_ASYNCHRONOUS:异步取消:在任意时间取消
voidpthread_testcancel(void);
调用该函数自己设置取消点。
线程并发度:
intpthread_setconcurrency(intnew_level);
告诉系统我们希望并发运行多少线程。系统不一定采纳。
level=0可以撤销之前调用的set设置的level值,由系统自己决定并发度。
intpthread_getconcurrency(void);
返回当前的并发度。如果之前没有调用set设置该值函数返回0.
线程私有数据:
创建一个键,进程中的所有线程共用这个键,但是每个线程把这个键和不同的线程私有数据地址关联,创建新键时线程数据地址设为null。析构函数,当线程调用pthread_exit或返回时,正常退出析构函数就会被调用。
intpthread_key_create(pthread_key_tkeyp, void (*destructor)(void *));
创建一个键和一个析构函数。
intpthread_key_delete(pthread_key_t*key);
取消键与线程私有数据值之间的关联。
pthread_once_tinitflag = PTHREAD_ONCE_INIT
initflag是一个全局变量或静态变量。
intpthread_once(pthread_once_tinitflag,void (*initfn)(void));
该函数用来能保证initfn函数只被调用一次。
intpthread_setspecific(pthread_key_tkey, const void *value);
键创建之后,调用该函数把键和线程私有数据关联起来。
void*pthread_getspecific(pthread_key_tkey);
获取线程私有数据地址,返回线程私有数据,如果没有值与键关联返回NULL。
线程和fork:
在线程中调用fork之后子进程的线程继承了互斥量、读写锁和条件变量的状态。
intpthread_atfork(void(*prepare)(void), void (*parent)(void), void(*child)(void));
用来安装三个清理锁的函数。
prepare函数在fork调用之前调用获取父进程定义的所有锁;
parent函数在fork返回之前的父进程中调用,解锁prepare获取的所有锁;
child函数在fork返回之前的子进程中调用,解锁prepare获取的所有锁。
#####################################################
线程相关其它库函数
#####################################################
线程和信号:
成功int的函数成功返回0,失败返回错误码。
#include<signal.h>
intpthread_sigmask(inthow, const sigset_t *set, sigset_t *oldset);
用于多线程。
oldset如果非NULL,oldset返回进程当前的信号屏蔽字。
set如果非NULL,根据how来修改set中的信号屏蔽字。
set如果为NULL,信号屏蔽字不变。
how:
SIG_BLOCK:阻塞,SIGKILL和SIGSTOP不能阻塞。信号屏蔽字是当前信号屏蔽字和set的并集。设置阻塞后的信号进程不处理该信号,所以该信号是未决的。
SIG_UNBLOCK:解阻塞,信号屏蔽字是当前信号屏蔽字和set的补集的交集。
SIG_SETMASK:设置掩码,信号屏蔽字是set指向的信号集。
intsigwait(constsigset_t *set, int *sig);
等待一个或多个信号发生。
set是等待的信号集,sig指向的整数获取信号。
intpthread_kill(pthread_tthread, int signo);
把信号signo发送到线程thread。
线程安全(重入):
如果一个函数在同一时刻被多个线程调用,就称这个函数是线程安全的,有一部分函数不能保证线程安全,也就是不可重入的,posix提供了这些函数的可重入版本(也就是带有_r的函数)。
#include<stdio.h>
intftrylockfile(FILE*fp);
成功返回0,失败返回非0.
锁定fp,但是不阻塞,如果别的线程已经锁定fp就返回。
voidflockfile(FILE*fp);
调用lock来锁定fp,别的线程不能使用fp。如果fp已经被别的线程锁定就阻塞。
voidfunlockfile(FILE*fp);
解锁fp,使别的线程能够使用fp。
intgetchar_unlocked(void);
intgetc_unlocked(FILE*fp);
这两个函数成功返回下一个字符,到达文件结尾或出错返回EOF。
intputchar_unlocked(intc);
intputc_unlocked(intc, FILE *fp);
这两个函数成功返回c,出错返回EOF。
未完待续......
APUE: 线程相关库函数