多线程使用

    科技2022-07-13  129

    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

    Processed: 0.017, SQL: 8