首页 > 代码库 > 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);

可以同时管理stackaddrstacksize


intpthread_attr_getstack(pthread_attr_t*attr, void **stackaddr, size_t *stacksize);

读取stackaddrstacksize


线程栈的大小:

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如果非NULLoldset返回进程当前的信号屏蔽字。

set如果非NULL,根据how来修改set中的信号屏蔽字。

set如果为NULL,信号屏蔽字不变。


how:

SIG_BLOCK:阻塞,SIGKILLSIGSTOP不能阻塞。信号屏蔽字是当前信号屏蔽字和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: 线程相关库函数