1. POSIX 线程标准
POSIX线程标准(POXIS Threads,缩写为Pthreads)是POSIX的线程标准,定义了一系列操作线程
的API。
1.1 POSIX标准
POSIX标准,POSIX表示可移植操作系统接口,即Portable Operating System Interface of
UNIX,缩写为POSIX。POSIX 标准定义了操作系统为应用程序提供的接口标准,是IEEE为要在各种
UNIX操作系统上运行的软件而定义的一系列 API 标准的总称,其正式称呼为IEEE 1003,而国际标
准名称为ISO/IEC 9945。
20世纪80年代,unix厂商视图增加一些新的、往往不兼容的特性使特们的程序体现差异化,这样
导致通用性降低,为阻止这一趋势,IEEE开始努力使unix进行标准化开发,后来由 Richard Stallman
命名为“Posix”,从而就得到了一系列标准,称作Posix标准。这套标准涵盖了很多方面,比如Unix系
统调用的C语言接口、shell程序和工具、线程及网络编程。
1.2 Linux上的线程库
Linux上没有真正意义的线程,使用进程来模拟,属于用户级线程,位于libpthread共享库,
遵循POSIX标准。Linux最有名的两个线程库:LinuxThreads 和 NPTL。 Linux从内核2.6开始,
多线程已经使用NPTL技术。查看系统使用的线程库,getconf GNU_LIBPTHREAD_VERSION。
1.3 线程API
当前我使用的操作系统CentOS Linux release 7.4.1708,线程库查看如下:
[root@host122 ~]# getconf GNU_LIBPTHREAD_VERSION
NPTL 2.17
查看该系统支持的线程API:
[root@host122 ~]# man -k pthread
pthread_atfork (3p) - register fork handlers
pthread_attr_destroy (3) - initialize and destroy thread attributes object
pthread_attr_getaffinity_np (3) - set/get CPU affinity attribute in thread attributes object
pthread_attr_getdetachstate (3) - set/get detach state attribute in thread attributes object
pthread_attr_getguardsize (3) - set/get guard size attribute in thread attributes object
pthread_attr_getinheritsched (3) - set/get inherit-scheduler attribute in thread attributes object
pthread_attr_getschedparam (3) - set/get scheduling parameter attributes in thread attributes object
pthread_attr_getschedpolicy (3) - set/get scheduling policy attribute in thread attributes object
pthread_attr_getscope (3) - set/get contention scope attribute in thread attributes object
pthread_attr_getstack (3) - set/get stack attributes in thread attributes object
pthread_attr_getstackaddr (3) - set/get stack address attribute in thread attributes object
pthread_attr_getstacksize (3) - set/get stack size attribute in thread attributes object
pthread_attr_init (3) - initialize and destroy thread attributes object
pthread_attr_setaffinity_np (3) - set/get CPU affinity attribute in thread attributes object
pthread_attr_setdetachstate (3) - set/get detach state attribute in thread attributes object
pthread_attr_setguardsize (3) - set/get guard size attribute in thread attributes object
pthread_attr_setinheritsched (3) - set/get inherit-scheduler attribute in thread attributes object
pthread_attr_setschedparam (3) - set/get scheduling parameter attributes in thread attributes object
pthread_attr_setschedpolicy (3) - set/get scheduling policy attribute in thread attributes object
pthread_attr_setscope (3) - set/get contention scope attribute in thread attributes object
pthread_attr_setstack (3) - set/get stack attributes in thread attributes object
pthread_attr_setstackaddr (3) - set/get stack address attribute in thread attributes object
pthread_attr_setstacksize (3) - set/get stack size attribute in thread attributes object
pthread_barrierattr_destroy (3p) - destroy and initialize the barrier attributes object (ADVANCED REALTIME THREADS)
pthread_barrierattr_getpshared (3p) - get and set the process-shared attribute of the barrier attributes object (ADVANCED REALTIME THREADS)
pthread_barrierattr_init (3p) - destroy and initialize the barrier attributes object (ADVANCED REALTIME THREADS)
pthread_barrierattr_setpshared (3p) - get and set the process-shared attribute of the barrier attributes object (ADVANCED REALTIME THREADS)
pthread_barrier_destroy (3p) - destroy and initialize a barrier object (ADVANCED REALTIME THREADS)
pthread_barrier_init (3p) - destroy and initialize a barrier object (ADVANCED REALTIME THREADS)
pthread_barrier_wait (3p) - synchronize at a barrier (ADVANCED REALTIME THREADS)
pthread_cancel (3) - send a cancellation request to a thread
pthread_cleanup_pop (3) - push and pop thread cancellation clean-up handlers
pthread_cleanup_pop_restore_np (3) - push and pop thread cancellation clean-up handlers while saving cancelability type
pthread_cleanup_push (3) - push and pop thread cancellation clean-up handlers
pthread_cleanup_push_defer_np (3) - push and pop thread cancellation clean-up handlers while saving cancelability type
pthread_condattr_destroy (3p) - destroy and initialize the condition variable attributes object
pthread_condattr_getclock (3p) - get and set the clock selection condition variable attribute (ADVANCED REALTIME)
pthread_condattr_getpshared (3p) - get and set the process-shared condition variable attributes
pthread_condattr_init (3p) - destroy and initialize the condition variable attributes object
pthread_condattr_setclock (3p) - get and set the clock selection condition variable attribute (ADVANCED REALTIME)
pthread_condattr_setpshared (3p) - get and set the process-shared condition variable attributes
pthread_cond_broadcast (3p) - broadcast or signal a condition
pthread_cond_destroy (3p) - destroy and initialize condition variables
pthread_cond_init (3p) - destroy and initialize condition variables
pthread_cond_signal (3p) - broadcast or signal a condition
pthread_cond_timedwait (3p) - wait on a condition
pthread_cond_wait (3p) - wait on a condition
pthread_create (3) - create a new thread
pthread_detach (3) - detach a thread
pthread_equal (3) - compare thread IDs
pthread_exit (3) - terminate calling thread
pthread_getaffinity_np (3) - set/get CPU affinity of a thread
pthread_getattr_np (3) - get attributes of created thread
pthread_getconcurrency (3) - set/get the concurrency level
pthread_getcpuclockid (3) - retrieve ID of a thread's CPU time clock
pthread_getname_np (3) - set/get the name of a thread
pthread_getschedparam (3) - set/get scheduling policy and parameters of a thread
pthread_getspecific (3p) - thread-specific data management
pthread.h (0p) - threads
pthread_join (3) - join with a terminated thread
pthread_key_create (3p) - thread-specific data key creation
pthread_key_delete (3p) - thread-specific data key deletion
pthread_kill (3) - send a signal to a thread
pthread_kill_other_threads_np (3) - terminate all other threads in process
pthread_mutexattr_destroy (3p) - destroy and initialize the mutex attributes object
pthread_mutexattr_getprioceiling (3p) - get and set the prioceiling attribute of the mutex attributes object (REALTIME THREADS)
pthread_mutexattr_getprotocol (3p) - get and set the protocol attribute of the mutex attributes object (REALTIME THREADS)
pthread_mutexattr_getpshared (3p) - get and set the process-shared attribute
pthread_mutexattr_getrobust (3p) - get and set the mutex robust attribute
pthread_mutexattr_gettype (3p) - get and set the mutex type attribute
pthread_mutexattr_init (3p) - destroy and initialize the mutex attributes object
pthread_mutexattr_setprioceiling (3p) - get and set the prioceiling attribute of the mutex attributes object (REALTIME THREADS)
pthread_mutexattr_setprotocol (3p) - get and set the protocol attribute of the mutex attributes object (REALTIME THREADS)
pthread_mutexattr_setpshared (3p) - get and set the process-shared attribute
pthread_mutexattr_setrobust (3p) - get and set the mutex robust attribute
pthread_mutexattr_settype (3p) - get and set the mutex type attribute
pthread_mutex_consistent (3p) - mark state protected by robust mutex as consistent
pthread_mutex_destroy (3p) - destroy and initialize a mutex
pthread_mutex_getprioceiling (3p) - get and set the priority ceiling of a mutex (REALTIME THREADS)
pthread_mutex_init (3p) - destroy and initialize a mutex
pthread_mutex_lock (3p) - lock and unlock a mutex
pthread_mutex_setprioceiling (3p) - get and set the priority ceiling of a mutex (REALTIME THREADS)
pthread_mutex_timedlock (3p) - lock a mutex (ADVANCED REALTIME)
pthread_mutex_trylock (3p) - lock and unlock a mutex
pthread_mutex_unlock (3p) - lock and unlock a mutex
pthread_once (3p) - dynamic package initialization
pthread_rwlockattr_destroy (3p) - destroy and initialize the read-write lock attributes object
pthread_rwlockattr_getpshared (3p) - get and set the process-shared attribute of the read-write lock attributes object
pthread_rwlockattr_init (3p) - destroy and initialize the read-write lock attributes object
pthread_rwlockattr_setpshared (3p) - get and set the process-shared attribute of the read-write lock attributes object
pthread_rwlock_destroy (3p) - destroy and initialize a read-write lock object
pthread_rwlock_init (3p) - destroy and initialize a read-write lock object
pthread_rwlock_rdlock (3p) - lock a read-write lock object for reading
pthread_rwlock_timedrdlock (3p) - lock a read-write lock for reading
pthread_rwlock_timedwrlock (3p) - lock a read-write lock for writing
pthread_rwlock_tryrdlock (3p) - lock a read-write lock object for reading
pthread_rwlock_trywrlock (3p) - lock a read-write lock object for writing
pthread_rwlock_unlock (3p) - unlock a read-write lock object
pthread_rwlock_wrlock (3p) - lock a read-write lock object for writing
pthreads (7) - POSIX threads
pthread_self (3) - obtain ID of the calling thread
pthread_setaffinity_np (3) - set/get CPU affinity of a thread
pthread_setcancelstate (3) - set cancelability state and type
pthread_setcanceltype (3) - set cancelability state and type
pthread_setconcurrency (3) - set/get the concurrency level
pthread_setname_np (3) - set/get the name of a thread
pthread_setschedparam (3) - set/get scheduling policy and parameters of a thread
pthread_setschedprio (3) - set scheduling priority of a thread
pthread_setspecific (3p) - thread-specific data management
pthread_sigmask (3) - examine and change mask of blocked signals
pthread_sigqueue (3) - queue a signal and data to a thread
pthread_spin_destroy (3p) - destroy or initialize a spin lock object (ADVANCED REALTIME THREADS)
pthread_spin_init (3p) - destroy or initialize a spin lock object (ADVANCED REALTIME THREADS)
pthread_spin_lock (3p) - lock a spin lock object (ADVANCED REALTIME THREADS)
pthread_spin_trylock (3p) - lock a spin lock object (ADVANCED REALTIME THREADS)
pthread_spin_unlock (3p) - unlock a spin lock object (ADVANCED REALTIME THREADS)
pthread_testcancel (3) - request delivery of any pending cancellation request
pthread_timedjoin_np (3) - try to join with a terminated thread
pthread_tryjoin_np (3) - try to join with a terminated thread
pthread_yield (3) - yield the processor
vfs_aio_pthread (8) - implement async I/O in Samba vfs using a pthread pool
NPTL 源码
http://ftp.gnu.org/pub/gnu/glibc/glibc-2.9.tar.gz
或者
https://sourceforge.net/projects/nuttx/
2. 常用线程API介绍
2.1 创建线程 pthread_create
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
参数说明:
thread :线程号
attr :线程属性
(*start_routine) (void *) :线程运行函数的起始地址
arg :运行函数的参数
2.2 等待线程结束 pthread_join
int pthread_join(pthread_t thread, void **retval);
阻塞直到等待id为thread的线程退出,可以通过传出参数value_ptr获取线程退出状态,线程退出时
系统进行线程使用的资源的回收(如线程内部申请的动态内存、信号量等)。这个函数可以类比
进程中使用的wait, waitpid函数。
参数说明:
thread : 线程号
retval : 线程运行函数的返回值
2.3 互斥锁加锁 pthread_mutex_lock
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
2.4 互斥锁解锁 pthread_mutex_unlock
int pthread_mutex_unlock(pthread_mutex_t *mutex);
2.5 线程分离 pthread_detach
int pthread_detach(pthread_t thread);
线程分两种:joinable 或者 detach。对于POSIX线程,除非线程是被分离了的,否则在线程
退出时,它的资源是不会被释放的,需要调用pthread_join回收。
pthread_detach 函数使子线程主动与主线程断开关系,该子线程结束后其状态不能由其他线程
获取,而子线程自身自动释放资源,多用于网络、多线程服务器。
参数说明:
thread : 线程号
2.6 线程退出 pthread_exit
void pthread_exit(void *retval);
线程可以隐式退出,也可以显式退出。
参数说明:
retval: 只要pthread_join中的第二个参数不是NULL,这个值将被传递给pthread_join函数
的第二个参数。
2.7 线程取消 pthread_cancel
int pthread_cancel(pthread_t thread);
功能是给线程发送取消信号,使线程从取消点退出。
该函数执行成功也不一定能取消掉指定线程的执行,因为这个函数线程执行函数进到内核时才会
被杀掉,如果用户一直运行在用户态不进到内核态也就无法取消线程的执行,此时可以使用
pthread_testcancel函数进到内核从而能够取消掉该线程的执行。
线程处于PTHREAD_CANCEL_ENABLE 状态,它就接受取消请求,如果线程处处于
PTHREAD_CANCEL_DISABLE 状态,取消请求就会被保持在挂起状态。默认情况下,线程处于
PTHREAD_CANCEL_ENABLE状态。
根据POSIX标准,pthread_join()、pthread_testcancel()、pthread_cond_wait()、
pthread_cond_timedwait()、sem_wait()、sigwait()等函数以及read()、write()等会
引起阻塞的系统调用都是Cancelation-point,而其他pthread函数都不会引起Cancelation动作。
使用man -7 pthreads 查看取消点相关内容。
参数说明:
thread : 要取消的线程id
2.7.1 线程取消涉及的内部属性
线程取消涉及的函数如下:
设置取消状态:
int pthread_setcancelstate(int state, int *oldstate);
设置取消类型
int pthread_setcanceltype(int type, int *oldtype);
当线程将退出作为对取消请求的响应时,取消类型允许线程控制它在什么地方退出,包括:
PTHREAD_CANCEL_DEFERRED 时,线程只能在特定的几个取消点上响应取消请求,默认值
PTHREAD_CANCEL_ASYNCHRONOUS 时,线程在任何时候都可以响应取消请求
2.8 线程条件处理发送信号 pthread_cond_signal
pthread_cond_signal函数的作用是发送一个信号给另外一个正
在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行.如果没有线程处在阻塞等待状态, pthread_cond_signal也会成功返回。
使用pthread_cond_signal不会有“惊群现象”产生,他最多只给
一个线程发信号。假如有多个线程正在阻塞等待着这个条件变量的话,那么是根据各等待线程优先级
的高低确定哪个线程接收到信号开始继续执行。如果各线程优先级相同,则根据等待时间的长短来确
定哪个线程获得信号。
在LinuxThreads或者NPTL里面有两个队列,分别是cond_wait队
列和mutex_lock队列, cond_signal只是让线程从cond_wait队列移到mutex_lock队列,而不用
返回到用户空间,不会有性能的损耗。
该函数对应pthread_cond_wait, 同类型函数
pthread_cond_broadcast。
int pthread_cond_signal(pthread_cond_t *cond);
参数说明:
cond : 线程条件变量
2.9 线程条件处理广播信号 pthread_cond_broadcast
int pthread_cond_broadcast(pthread_cond_t *cond);
参数说明:
cond : 线程条件变量
2.10 线程等待条件变量 pthread_cond_wait
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
线程等待处于挂起状态。为什么需要mutex见参考中列出的内容。
参数说明:
cond :线程条件变量
mutex :互斥锁
超时等待条件变量函数:
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
abstime 参数需要注意:
POSIX提供了多种时钟类型,其中包括以下两种:
CLOCK_REALTIME: Systemwide realtime clock. 系统范围内的实时时钟,是个软件时钟,
可以通过命令等方式修改该系统时间.
CLOCK_MONOTONIC:Represents monotonic time. Cannot be set. 表示单调时间,为系统
起机时到现在的时间,不能被设置跟修改.
pthread_cond_timedwait()在没有设置条件变量属性的时候,默认用的是CLOCK_REALTIME软件
时间,因此在极端情况下会出现实际等待的时间与设置的超时时间不同。
2.11 pthread_key_create
分配用于标识进程中线程特定数据的键。
进程中并不能创建无限个的pthread_key_t变量。Linux中可以
通过PTHREAD_KEY_MAX(定义于limits.h文件中)或者系统调用sysconf(_SC_THREAD_KEYS_MAX)
来确定当前系统最多支持多少个键。Linux中默认是1024个键。
查看pthread_key_create.c 源码实现文件,可以更好的理解
pthread_key_create 函数,里面用了个for循环,实际内部创建的是一个数组。
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
参数说明:
key :线程特定数据的标识键
(*destructor)(void*) :线程结束时,系统将调用这个函数来释放绑定在这个键上的内存
对应的销毁函数
int pthread_key_delete (pthread_key_t key);
2.12 设置线程数据共享 pthread_setspecific
设置变量value 与 pthread_key_t 类型的变量key进行关联。
pthread_getpecific和pthread_setspecific提供了在同一个线程中不同函数间共享数据即线程
存储的一种方法。
c++11 提供了一个新的数据类型 thread_local,该数据类型的变量在每个线程中都是一个副本,
进行修改等处理不影响其他线程内保存的该变量的值。
int pthread_setspecific(pthread_key_t key, const void *value);
2.13 读取线程数据共享 pthread_getspecific
void *pthread_getspecific(pthread_key_t key);
2.14 pthread_once
只执行1次的设置函数
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));
pthread_once_t once_control = PTHREAD_ONCE_INIT;
2.15 线程读写锁
读锁:
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
写锁:
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
解锁:
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
3. 参考
POSIX 线程详解(经典必看)
https://www.cnblogs.com/sunminmin/p/4479952.html
GLIBC中NPTL线程实现代码阅读
https://blog.csdn.net/whuzm08/article/details/53537631
pthread_cond_wait 为什么需要传递 mutex 参数?
https://www.zhihu.com/question/24116967