一、线程基本操作函数

pthread_equal()——比较线程ID
  1.函数功能:比较两个线程的线程标识符

项目 说明
函数原型 int pthread_equal(pthread_t t1, pthread_t t2);
头文件 pthread.h
参数说明 t1:线程标识符1
t2:线程标识符2
返回值 t1与t2相等,将返回非零,否则返回零。

若任一线程标识符为无效,则结果无法预测

注意

pthread_self()——获取调用线程的ID

1.函数功能:获取调用线程的ID,该值与创建这个线程的pthread_create(3)调用中在*thread中返回的值相同。

项目 说明
函数原型 pthread_t pthread_self(void);
头文件 pthread.h
参数说明
返回值 返回调用线程的ID
注意

pthread_create()——创建线程

 1.函数功能:创建一个某种特性的线程,线程中执行线程函数。

    在返回之前,成功调用pthread_create()将新线程的ID存储在线程所指向的缓冲区中;这个标识符用于在后续调用其他pthreads函数时引用该线程。

    新线程继承了创建线程的信号掩码的副本(pthread_sigmask(3))。新线程的挂起信号集为空(sigpending(2))。新线程不继承创建线程的备用信号堆栈(sigaltstack(2))。

    新线程继承调用线程的浮点环境(fenv(3))。

    新线程的cpu时间时钟的初始值是0(参见pthread_getcpuclockid(3))。

项目 说明
函数原型 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
头文件 pthread.h
thread:线程标记变量
指向的内存单元被设置为新创建线程的线程ID
attr:线程属性
指向pthread_attr_t结构体,用pthread_attr_init(3)和相关函数进行初始化
若设置为NULL,则为默认属性
start_routine:自定义线程函数
线程的资源分配后,所运行的单元
arg:线程函数的传参
若想传递多参数则可将参数放入结构中
返回值 成功时返回0.
失败时返回错误号,*thread 内容是未定义的。.
注意

 2.新线程终止方式:

    1️⃣调用pthread_exit(3),指定一个退出状态值,该值可以被调用pthread_join(3)的进程中的其他线程使用。

    2️⃣从start_routine()返回。这相当于用return语句中提供的值调用pthread_exit(3)

    3️⃣被取消(参见pthread_cancel(3))。

    4️⃣进程中的任何线程调用exit(3),或者主线程执行main()返回。这将导致进程中所有线程的终止

  3.错误代码:

    EAGAIN:资源不足,无法创建其他线程;

    EINVAL:线程的属性非法。

    EPERM:没有权限设置attr中指定的调度策略和参数。

 pthread_exit() ——结束线程

  1.函数功能:终止调用线程。

    由pthread_cleanup_push(3)建立的任何尚未弹出的清理处理程序都将弹出(与它们被推送的顺序相反)并执行。如果线程有任何特定于线程的数据,那么,在执行清理处理程序之后,将以未指定的顺序调用相应的析构函数。

    当线程终止时,进程共享的资源(例如互斥体、条件变量、信号量和文件描述符)不会被释放,使用atexit(3)注册的函数也不会被调用

项目 说明
函数原型 void pthread_exit(void *retval);
头文件 pthread.h
参数说明 retval:无类型指针
(该值与传给启动例程的单个参数类似,进程中其他线程可调用pthread_join()访问该指针)
返回值 无返回值
注意

2.单线程退出方式(不终止整个进程的情况下停止它的控制流)

    (1)线程只是从启动例程中返回,返回值是线程的退出码

    (2)线程可被同一进程中的其他线程取消

    (3)线程调用pthread_exit ()

 pthread_join() ——阻塞线程

  1.函数功能:等待由thread指定的线程结束。如果该线程已经终止,则pthread_join()立即返回。由thread指定的线程必须是可接合的。

    若retval不是NULL,那么pthread_join()将目标线程的退出状态(即目标线程提供给pthread_exit(3)的值)复制到retval所指向的位置。如果目标线程被取消,那么PTHREAD_CANCELED将被放置在retval所指向的位置。

    若多个线程同时尝试与同一个线程连接,结果是未定义的。如果调用pthread_join()的线程被取消,那么目标线程仍然是可接合的(也就是说,它不会被分离)。

 【调用线程将一直阻塞,直到指定的线程调用pthread_exit(),从启动例程中返回或被取消。若线程只是从它的启动例程返回,retval将包含返回码,若线程被取消,由retval指定的内存单元就置为PTHREAD_CANCELED

项目 说明
函数原型 int pthread_join(pthread_t thread, void **retval);
头文件 pthread.h
参数说明 thread:线程标识符
(pthread_create()创建成功的值)
retval:线程返回值可用来存储被等待线程的返回值
(该参数传出时通常用一个指针变量的地址表示)
返回值 成功时返回0.失败时返回错误值.
注意

2.错误代码:

  ESRCH:没有找到与给定的线程ID相对应的线程。

  EDEADLK:检测到死锁,如一个线程等待其本身,或者线程A和线程B互相等待。

  EINVAL:与给定的线程ID相对应的线程是分离线程(线程不是一个可接合的线程,另一个线程已经在等待加入这个线程)。

 pthread_cancel()——取消线程

  1.函数功能:默认情况下,该函数会使thread标识的线程的行为表现为如同调用了参数PTHREAD_CANCELED的pthread_exit(),并不是等待线程终止,仅仅提出请求。

    向线程发送一个取消请求,目标线程是否以及何时响应取消请求取决于该线程控制的两个属性:可取消性状态和类型。

    线程的取消状态pthread_setcancelstate(3)决定,可以是启用(新线程的默认状态)或禁用。如果一个线程禁用了取消,那么取消请求将保持在队列中,直到线程启用取消。如果一个线程启用了取消,那么它的取消类型决定何时取消。

    线程的取消类型pthread_setcanceltype(3)决定,可以是异步的,也可以是延迟的(新线程的默认值)。异步可取消性意味着线程可以在任何时候被取消(通常是立即,但系统不保证这一点)。延迟取消性意味着取消将被延迟,直到下一个线程调用一个作为取消点的函数。pthreads(7)中提供了一个函数列表,这些函数是或可能是取消点。

项目 说明
函数原型 int pthread_cancel(pthread_t thread);
头文件 pthread.h
参数说明 thread:线程标识符
返回值 成功返回0,失败返回非零
注意

 2.取消请求被执行时,以下步骤会在线程中发生(按此顺序):

    1️⃣取消清理处理程序将弹出(与它们被推送的顺序相反)并被调用。(见pthread_cleanup_push(3))。

    2️⃣线程特定的数据析构函数将按未指定的顺序调用。(见pthread_key_create(3))。

    3️⃣线程终止。(见pthread_exit(3))

  上面的步骤是相对于pthread_cancel()调用异步发生的;pthread_cancel()的返回状态只是通知调用者取消请求是否成功排队。

  在一个被取消的线程终止后,使用pthread_join(3)与该线程的连接将获得PTHREAD_CANCELED作为线程的退出状态。(加入一个线程是知道取消已经完成的唯一方法。)

  3.错误代码:

    ESRCH:没有找到与给定线程ID相对应的线程。

 pthread_detach()——分离线程

  1.函数功能:指示应用程序在线程终止时,回收创建时detachstate属性设置为PTHREAD_CREATE_JOINABLE的线程的存储空间。

    若该线程尚未终止,该函数不会终止该进程。

    当对现有某个线程终止状态不感兴趣时则可使用pthread_detach函数让操作系统在线程退出时收回它所占的资源。

微信截图_20231210231938.jpg

2.错误代码:

  EINVAL: thread是分离线程。

  ESRCH: thread不是当前进程中有效的未分离的线程。

 线程清理函数

1.概念:

    线程可建立多个清理处理程序,处理程序记录在栈中,也就是说它们的执行顺序与注册时的顺序相反。

    这些函数操作调用线程的线程取消清理处理程序堆栈。清理处理器是一个在线程被取消时自动执行的函数(或在下面描述的各种其他情况下),如:它可解锁一个互斥锁,以便该进程中的其他线程可以使用该互斥锁。

 2.一个取消清理处理程序从堆栈中弹出,并在以下情况下执行:

    1️⃣当一个线程被取消时,所有堆叠的清理处理程序都会弹出,并以与它们被推送到堆栈的顺序相反的顺序执行。

    2️⃣当一个线程通过调用pthread_exit(3)终止时,所有的清理处理程序将按照前面的描述执行。(如果线程通过执行返回函数结束,则不会调用清理处理程序。)

    3️⃣当线程使用非零执行参数调用pthread_cleanup_pop()时,弹出并执行最顶层的清理处理程序。

  POSIX.1允许将pthread_cleanup_push()pthread_cleanup_pop()实现为宏,分别扩展为包含’{‘和’}’的文本。因此,调用者必须确保对这些函数的调用在同一个函数中配对,并且在相同的词法嵌套级别上配对。(换句话说,清理处理程序只在执行指定的代码段时建立。)

  若调用了pthread_cleanup_push()pthread_cleanup_pop()而没有匹配的调用,调用longjmp(3) (siglongjmp(3))将产生未定义的结果,因为跳跃缓冲区被setjmp(3) (sigsetjmp(3))填充了。同样,在清理处理程序中调用longjmp(3) (siglongjmp(3))会产生未定义的结果,除非在处理程序中也被setjmp(3) (sigsetjmp(3))填充。

 pthread_cleanup_push()——例程压栈

 1.函数功能:将例程推送到清理处理程序堆栈的顶部,当例程稍后被调用时,它将被给予arg作为它的参数。

微信截图_20231210232020.jpg

pthread_cleanup_pop()——例程出栈
  1.函数功能:会移除堆栈顶部的例程,若execute为非零值,可以选择执行它。

微信截图_20231210232027.jpg

二、线程同步函数

(一)互斥量(互斥锁)

pthread_mutex_init()——初始化互斥锁

 1.函数功能:attr指定的属性来初始化被互斥对象引用的互斥对象。

    若attrNULL,则使用默认的互斥锁属性;其效果与传递默认互斥锁属性对象的地址相同。在初始化成功后,互斥对象的状态被初始化和解锁。

    只有互斥锁本身可以用来执行同步。在调用pthread_mutex_lock()、pthread_mutex_trylock()、pthread_mutex_unlock()和pthread_mutex_destroy()时引用互斥锁副本的结果是未定义的。

    试图初始化一个已经初始化的互斥量会导致未定义的行为。

    在默认互斥对象属性合适的情况下,宏PTHREAD_MUTEX_INITIALIZER可以用来初始化互斥对象。其效果应该相当于动态初始化,调用pthread_mutex_init(),参数attr指定为NULL,除非不执行错误检查。

微信截图_20231210232121.jpg

pthread_mutex_destroy()——销毁互斥锁

  1.函数功能:销毁被互斥对象引用的互斥对象;这个互斥对象实际上是未初始化的。

    一个实现可能导致pthread_mutex_destroy()将互斥对象引用的值设置为无效值

    一个被销毁的互斥对象可以使用pthread_mutex_init()重新初始化;在对象被销毁后,引用该对象的结果是未定义的。

    销毁一个已初始化且未锁定的互斥对象应该是安全的。试图销毁一个锁定的互斥对象,或者被另一个线程引用的互斥对象(例如,在pthread_cond_timedwait()pthread_cond_wait()中使用的互斥对象),会导致未定义的行为。

微信截图_20231210232129.jpg

pthread_mutex_lock()——对互斥量加锁
 1.函数功能:mutex进行加锁,若互斥锁已被另一线程锁定,调用线程将会阻塞,直到互斥锁可用位置。

pthread_mutex_trylock()——对互斥量尝试加锁

 1.函数功能:默认等价于pthread_mutex_lock(),除非被互斥对象被锁定,调用立即返回,若互斥对象类型是PTHREAD_MUTEX_RECURSIVE且该互斥对象的当前归调用线程所有,那么互斥锁计数将假1.

    或者说若线程不希望被阻塞,则可使用该函数对互斥量进行加锁,若互斥量未锁住则将会锁住并不会阻塞并返回0,若互斥量已被锁住则会失败,不会锁住返回EBUSY

微信截图_20231210232830.jpg

pthread_mutex_unlock()——对互斥量解锁

  1.函数功能:互斥锁释放的方式取决于互斥锁的type属性。若在被互斥对象引用的互斥对象上有线程被阻塞,导致互斥对象可用,调度策略将决定哪个线程应该获得互斥对象。

(在PTHREAD_MUTEX_RECURSIVE互斥对象的情况下,当计数为0且调用该互斥对象的线程不再拥有该互斥对象上的任何锁时,互斥对象将变为可用。)

微信截图_20231210232943.jpg

(二)读写锁

pthread_rwlock_init()——初始化读写锁

 1.函数功能:分配使用rwlock引用的读写锁所需的任何资源,并使用attr引用的属性将锁初始化为解锁状态。如果attrNULL,则默认读写锁属性为应使用;其效果与传递默认读写锁属性对象的地址相同。一旦初始化,锁可以被使用任意次数而不需要重新初始化。

微信截图_20231210232950.jpg

pthread_rwlock_destroy()——销毁读写锁
  1.函数功能:销毁rwlock所引用的读写锁对象,并释放锁所使用的所有资源

微信截图_20231210233050.jpg

pthread_rwlock_rdlock()——读模式加锁

  1.函数功能:rwlock引用的读写锁应用一个读锁。如果写线程没有持有锁,并且锁上没有阻塞写线程,那么调用线程就会获得读锁。 如果线程执行调度选项支持,参与锁的线程执行的调度策略SCHED_FIFO SCHED_RR,或调用线程不得获得锁如果一个作家持有的锁或者作家锁上的优先级高于或等于受阻;否则,调用线程将获得锁。

如果支持线程执行调度选项,并且锁中涉及的线程执行sched_散发调度策略,那么如果写线程持有锁,或者更高或同等优先级的写线程被锁阻塞,则调用线程将不会获得锁;否则,调用线程将获得锁。

如果不支持Thread Execution Scheduling选项,那么当写入器没有持有锁且锁上有写入器阻塞时,调用线程是否获得锁是由实现定义的。如果写线程持有锁,那么调用线程将不会获得读锁。如果没有获得读锁,则调用线程将阻塞,直到获得该锁为止。如果调用线程持有写锁,则调用线程可能会死锁。

一个线程可以持有rwlock上的多个并发读锁(也就是说,成功调用pthread_rwlock_rdlock()函数n次)。如果是,应用程序应确保线程执行匹配的解锁(即,它调用pthread_rwlock_unlock()函数n次)。

一个实现可以保证同时应用于一个读写锁的最大读锁数量应由实现定义。如果超过这个最大值,pthread_rwlock_rdlock()函数可能会失败。

微信截图_20231210233139.jpg

pthread_rwlock_tryrdlock()——读模式尝试加锁
  1.函数功能:

微信截图_20231210233149.jpg

pthread_rwlock_wrlock()——写模式加锁

  1.函数功能:rwlock引用的读写锁应用写锁。如果没有其他线程(读线程或写线程)持有读写锁rwlock,则调用线程获得写锁。否则,线程将阻塞,直到它能够获得锁。如果调用线程在调用时持有读写锁(无论是读锁还是写锁),则调用线程可能会死锁。

  实现可能倾向于写程序而不是读程序,以避免写程序不足。

  如果使用未初始化的读写锁调用这些函数,则结果是未定义的。

  如果一个信号被传递给一个等待读写锁的线程进行写操作,那么在从信号处理程序返回后,该线程将继续等待读写锁进行写操作,就像它没有被中断一样。

微信截图_20231210233341.jpg

pthread_rwlock_trywrlock()——写模式尝试加锁
  1.函数功能:pthread_rwlock_wrlock()函数一样应用一个写锁,但如果当前有线程持有rwlock(用于读取或写入),则该函数将失败。

微信截图_20231210233356.jpg

pthread_rwlock_unlock()——解锁读写锁对象

  1.函数功能:释放rwlock引用的读写锁对象所持有的锁。如果读写锁rwlock没有被调用线程持有,那么结果是未定义的。

  如果调用这个函数来释放读写锁对象的读锁,并且这个读写锁对象当前持有其他读锁,那么读写锁对象将保持在读锁定状态。如果这个函数释放了这个读写锁对象的最后一个读锁,那么读写锁对象将处于解锁状态,没有所有者。

  如果调用这个函数来释放这个读写锁对象的写锁,那么读写锁对象将处于解锁状态。

  当锁可用时,如果锁上有线程被阻塞,则调度策略将决定哪个(多个)线程应该获得锁。如果支持线程执行调度选项,当执行调度策略SCHED_FIFO、SCHED_RRsched_零星的线程正在等待锁时,它们将在锁可用时按优先级顺序获取锁。对于同等优先级的线程,写锁应优先于读锁。如果不支持线程执行调度选项,那么写锁是否优先于读锁是由实现定义的。

  如果使用未初始化的读写锁调用此函数,则结果是未定义的。

微信截图_20231210233437.jpg

(三)条件变量

pthread_cond_init()——初始化条件变量

  1.函数功能:attr引用的属性初始化cond引用的条件变量。如果attrNULL,则默认条件变量属性为应使用;其效果与传递默认条件变量属性对象的地址相同。初始化成功后,条件变量的状态将被初始化。

  只有cond本身可以用于执行同步。在调用pthread_cond_wait()、pthread_cond_timedwait()、pthread_cond_signal()、pthread_cond_broadcast()和pthread_cond_destroy()时引用cond副本的结果是未定义的。

  试图初始化一个已经初始化的条件变量会导致未定义的行为。

  在使用默认条件变量属性的情况下,可以使用宏PTHREAD_COND_INITIALIZER来初始化条件变量。其效果应该相当于动态初始化,即调用pthread_cond_init(),参数attr指定为NULL,但不执行错误检查。

微信截图_20231210233517.jpg

pthread_cond_destroy()——销毁条件变量

  1.函数功能:将销毁cond指定的条件变量;实际上,该对象变为未初始化。

 一个实现可能导致pthread_cond_destroy()cond引用的对象设置为一个无效的值。被销毁的条件变量对象可以使用pthread_cond_init()重新初始化;在对象被销毁后,引用该对象的结果是未定义的。

   销毁一个已初始化且当前没有线程被阻塞的条件变量应该是安全的。试图销毁当前阻塞其他线程的条件变量会导致未定义的行为。

微信截图_20231210233606.jpg

pthread_cond_wait()——有条件的等待

  1.函数功能:等待条件变为真,若在给定的时间内条件不能满足,那么会生出一个代表出错码的返回变量。

  传递给pthread_cond_wait()的互斥量对条件进行保护,调用者把锁住的互斥量传给函数,函数把调用线程放在等待条件的线程列表上,然后对互斥量解锁,这两个操作是原子操作。返回时,互斥量再次被锁住。

 在条件变量上阻塞。应用程序应确保这些函数在调用线程锁定互斥的情况下被调用;否则,一个错误(对于PTHREAD_MUTEX_ERRORCHECK和健壮的互斥)或未定义的行为(对于其他互斥)结果

 会自动释放互斥量,并导致调用线程阻塞条件变量cond;这里的“原子”意思是“原子上”,即另一个线程访问互斥对象,然后是条件变量”。也就是说,如果另一个线程可以获得互斥锁about-to-block线程释放了它之后,然后随后调用pthread_cond_broadcast()或pthread_cond_signal()在该线程的行为就好像它是about-to-block线程阻塞后发布。

 成功返回时,互斥对象将被锁定,并由调用线程拥有。如果互斥对象是一个健壮的互斥对象,它的所有者在持有该互斥对象时终止了锁,并且状态是可恢复的,那么即使函数返回错误码,也应该获得该互斥对象。

 当使用条件变量时,总是有一个布尔谓词,其中包含与每个条件等待相关的共享变量,该谓词在线程应该继续时为真。pthread_cond_timedwait()或pthread_cond_wait()函数可能会出现虚假的唤醒。因为pthread_cond_timedwait()或pthread_cond_wait()的返回值并不意味着这个谓词的任何值,所以应该在这样的返回时重新计算谓词的值。

微信截图_20231210233644.jpg

pthread_cond_timedwait()——有条件的等待

  1.函数功能:pthread_cond_wait()类似,但需指定愿意等待时间,时间值是一个绝对数而不是相对数。故需使用gettimeofday()获取当前时间(timespec结构),后转换为timespec结构,如:

void maketimeout(struct timespec *tsp,long minutes)
{
	struct timaval now;
	gettimeofday(&now);
	tsp->tv_sec = now.tv_sec;
	tsp->tv_nsec = now.tv_usec *1000;
	tsp->tv_sec += minutes*60;
}

若时间值到了但条件还未出现则会重新获取互斥量然后返回错误ETIMEDOUT,成功返回时,线程需重新计算条件,因为其他的线程可能已经在运行并改变了条件。

微信截图_20231210233754.jpg

pthread_cond_signal()——信号一个条件
 1.函数功能:唤醒等待该条件的某个线程

微信截图_20231210233801.jpg

pthread_cond_signal()——信号一个条件
  1.函数功能:唤醒等待该条件的某个线程

微信截图_20231210233849.jpg

三、线程控制

(一)线程属性

1.基本概念:

    设置属性,可指定不同于缺省行为的行为。

    属性对象是不透明的,且不能通过赋值直接修改。

    初始化和配置属性后,属性便具有进程范围的作用域。

 2.使用方法:

    程序执行早期一次配置好所必须的状态规范。

    根据需要引用相应属性对象。

  3.主要优点:

    ①使用属性对象可增加代码可移植性。

    ②应用程序中状态规范已被简化

 pthread_attr_init()——初始化线程属性对象

 1.函数功能:用默认属性值初始化attr所指向的线程属性对象。存储空间是在执行期间由线程系统分配的。

微信截图_20231210233915.jpg

2.错误代码
ENOMEM:如果未分配足够的内存来初始化线程属性对象,将返回该值。
3.缺省属性值

微信截图_20231210233931.jpg

pthread_attr_destroy()——销毁线程属性对象
  1.函数功能:销毁一个线程属性对象对使用该对象创建的线程没有影响。

微信截图_20231210234014.jpg

2.错误代码
    EINVAL:指示tattr的值无效。

pthread_attr_getdetachstate()——获取分离状态属性
  1.函数功能:返回detachstate所指向的缓冲区中线程属性对象attr的分离状态属性。

微信截图_20231210234026.jpg

2.错误代码

    EINVAL:指示detachstatetattr的值无效。

 pthread_attr_setdetachstate()——设置分离状态属性

  1.函数功能:attr引用的线程属性对象的detachstate属性设置为detachstate中指定的值.

    分离状态属性确定使用线程属性对象attr创建的线程将以可接合状态还是分离状态创建。

微信截图_20231210234138.jpg

2.detachstate值:

    1️⃣PTHREAD_CREATE_DETACHED:使用attr创建的线程将以分离状态创建。

    2️⃣PTHREAD_CREATE_JOINABLE:使用attr创建的线程将以可接合状态创建,可获取线程终止状态 。

    在新初始化的线程属性对象中,分离状态属性的默认设置是PTHREAD_CREATE_JOINABLE

 pthread_attr_getstack()——在线程属性对象中获取堆栈属性

  1.函数功能:分别返回由attr在由stackaddrstacksize指向的缓冲区中引用的线程属性对象的堆栈地址和堆栈大小属性。

微信截图_20231210234206.jpg

pthread_attr_setstack()——在线程属性对象中设置堆栈属性

 1.函数功能:attr引用的线程属性对象的堆栈地址和堆栈大小属性分别设置为stackaddrstacksize中指定的值。这些属性指定了应该由使用thread attributes object attr创建的线程使用的堆栈的位置和大小。

    所分配的缓冲区的页面应该是可读可写的。

微信截图_20231210234214.jpg

pthread_attr_getstacksize()——在线程属性对象中获取堆栈大小属性
  1.函数功能:返回由attrstacksize指向的缓冲区中引用的线程属性对象的堆栈大小属性。

微信截图_20231210234304.jpg

 pthread_attr_setstacksize()——在线程属性对象中设置堆栈大小属性

  1.函数功能:attr引用的线程属性对象的堆栈大小属性设置为stacksize中指定的值。

  堆栈大小属性决定了将为使用线程属性对象attr创建的线程分配的最小大小(以字节为单位)。

微信截图_20231210234322.jpg

pthread_attr_getguardsize()——获取栈溢出保护区大小
 1.函数功能:返回由attr线程属性中guardsize指向的堆栈溢出保护区的大小。

微信截图_20231210234402.jpg

2.错误代码

  EINVAL:参数attr无效,参数guardsize无效,或参数guardsize包含无效值。

3.其他

    允许一致的实现将guardsize中包含的值向上舍入为可配置系统变量PAGESIZE的倍数。请参见sys/mman.h中的PAGESIZE。如果实现将guardsize的值向上舍入为PAGESIZE的倍数,则以guardsize(先前调用pthread_attr_setguardsize()时指定的溢出保护区大小)为单位存储对指定attrpthread_attr_getguardsize( )的调用。

 pthread_attr_setguardsize()——设置栈溢出保护区大小

 1.函数功能:将attr线程属性的堆栈溢出保护区设置为guardsize指定值。

    若guardsize>0,那么对于使用attr创建的每个新线程,系统会在线程堆栈的末尾分配一个至少有guardsize字节的额外区域,作为堆栈的保护区域(但请参阅BUGS)。

    若guardsize=0,那么使用attr创建的新线程将没有保护区域。

    默认保护大小与系统页面大小相同。

  若堆栈地址属性已经在attr中设置(使用pthread_attr_setstack(3)pthread_attr_setstackaddr(3)),这意味着调用者正在分配线程的堆栈,那么守护大小属性被忽略(即系统没有创建守护区域):处理堆栈溢出是应用程序的责任(可能通过使用mprotect(2)在它已分配的堆栈末端手动定义一个保护区域)。

微信截图_20231210234430.jpg

2.错误代码

EINVAL:参数attr无效,参数guardsize无效,或参数guardsize包含无效值。

 3.为应用程序提供guardsize属性的原因

    ①溢出保护可能会导致系统资源浪费。如果应用程序创建大量线程,并且已知这些线程永远不会溢出其栈,则可以关闭溢出保护区。通过关闭溢出保护区,可以节省系统资源。

    ②线程在栈上分配大型数据结构时,可能需要较大的溢出保护区来检测栈溢出。

 4.其他:

    guardsize参数提供了对栈指针溢出的保护。如果创建线程的栈时使用了保护功能,则实现会在栈的溢出端分配额外内存。此额外内存的作用与缓冲区一样,可以防止栈指针的栈溢出。如果应用程序溢出到此缓冲区中,这个错误可能会导致SIGSEGV信号被发送给该线程。

    如果guardsize为零,则不会为使用attr创建的线程提供溢出保护区。如果guardsize大于零,则会为每个使用attr创建的线程提供大小至少为guardsize字节的溢出保护区缺省情况下,线程具有实现定义的非零溢出保护区。

    允许合乎惯例的实现,将guardsize的值向上舍入为可配置的系统变量PAGESIZE的倍数。请参见sys/mman .h中的PAGESIZE。如果实现将guardsize的值向上舍人为PAGESIZE的倍数,则以guardsize(先前调用pthread_attr_setguardsize()时指定的溢出保护区大小)为单位存储对指定attrpthread_attr_getguardsize()的调用。

 pthread_getconcurrency()——获取并发级别

 1.函数功能:返回此进程的并发级别的当前值。

微信截图_20231210234504.jpg

pthread_setconcurrency()——设置并发级别

  1.函数功能:通知应用程序所需并发级别的实现,该级别在new_level中指定。该实现仅将此作为一个提示:POSIX.1没有指定调用pthread_setconcurrency()时应该提供的并发级别。

    将new_level指定为0指示实现按照其认为合适的方式管理并发级别。

微信截图_20231210234510.jpg

(二)同步属性

1.互斥量

pthread_mutexattr_init()——初始化互斥属性对象

  1.函数功能:实现定义的所有属性的默认值初始化一个互斥属性对象attr

    在一个互斥对象的属性对象被用来初始化一个或多个互斥对象之后,任何影响属性对象的函数(包括销毁)都不应影响任何先前初始化的互斥对象。

微信截图_20231210234606.jpg

pthread_mutexattr_destroy()——销毁互斥属性对象
  1.函数功能:销毁一个互斥属性对象;实际上,该对象变为未初始化。

微信截图_20231210234612.jpg

pthread_mutexattr_getpshared()——获取进程共享属性
 1.函数功能:将被attr引用的互斥对象的进程共享属性的值放在pshared所指向的位置中。

微信截图_20231210234653.jpg

pthread_mutexattr_setpshared()——设置进程共享属性
 1.函数功能:将被attr引用的互斥对象的进程共享属性的值设置为pshared中指定的值。

微信截图_20231210234704.jpg

2.共享属性值:

    PTHREAD_PROCESS_PRIVATE:使用该属性对象创建的互斥对象只能在初始化该互斥对象的同一进程中的线程之间共享。这是进程共享互斥属性的默认值。

    PTHREAD_PROCESS_SHARED:使用该属性对象创建的互斥对象可以在任何访问包含该对象的内存的线程之间共享,包括不同进程中的线程。

 pthread_mutexattr_gettype()——获取互斥类型属性

  1.函数功能:

微信截图_20231210234743.jpg

2.互斥量类型:

微信截图_20231210234752.jpg

2.读写锁
pthread_rwlockattr_init()——初始化一个读写锁属性对象
 1.函数功能:应该用实现定义的所有属性的默认值初始化一个读写锁属性对象attr。

微信截图_20231210234835.jpg

pthread_rwlockattr_destroy()——销毁一个读写锁属性对象
  1.函数功能:销毁一个读写锁属性对象

微信截图_20231210234850.jpg

pthread_rwlockattr_getpshared()——获取读写锁属性对象的进程共享属性
 1.函数功能:获取读写锁属性对象的进程共享属性

微信截图_20231210234957.jpg

pthread_rwlockattr_setpshared()——设置读写锁属性对象的进程共享属性
 1.函数功能:在由attr引用的初始化属性对象中设置进程共享属性。
  进程共享属性应当将PTHREAD_PROCESS_SHARED允许手术的读写锁的线程访问的内存分配读写锁的地方,即使在内存中分配读写锁,由多个进程共享。如果进程共享属性是PTHREAD_PROCESS_PRIVATE,读写锁只能由与初始化读写锁的线程在同一进程中创建的线程操作;如果不同进程的线程试图操作这样的读写锁,行为是未定义的。进程共享属性的默认值应该是PTHREAD_PROCESS_PRIVATE

微信截图_20231210235005.jpg

3.条件变量
pthread_condattr_init()——初始化条件变量属性对象
1.函数功能:实现中定义的所有属性的默认值初始化一个条件变量属性对象attr

pthread_condattr_destroy()——销毁条件变量属性对象
  1.函数功能:销毁一个条件变量属性对象

pthread_condattr_getpshared()——获取进程共享属性的值。
 1.函数功能:attr引用的attributes对象中获取进程共享属性的值。

pthread_condattr_setpshared()——设置进程共享属性。
  1.函数功能:在由attr引用的初始化属性对象中设置进程共享属性。

2.共享属性:
    进程共享属性被设置为PTHREAD_PROCESS_SHARED,以允许任何能够访问分配条件变量的内存的线程操作条件变量,即使该条件变量被分配在多个进程共享的内存中。如果进程共享属性是PTHREAD_PROCESS_PRIVATE,那么条件变量只能由与初始化条件变量的线程在同一进程中创建的线程操作;如果不同进程的线程试图操作这样一个条件变量,则行为是未定义的。该属性的默认值是PTHREAD_PROCESS_PRIVATE

四、私有数据

pthread_key_create ()——创建线程键:
 1.线程特定数据:
    单线程C程序有两类基本数据:局部数据和全局数据。
    多线程C程序,添加了第三类数据:线程特定数据。
    线程特定数据与全局数据非常相似,区别在于前者为线程专有。
    线程特定数据基于每线程进行维护。TSD(特定于线程的数据)是定义和引用线程专用数据的唯一方法。每个线程特定数据项都与一个作用于进程内所有线程的键关联。通过使用key,线程可以访问基于每线程进行维护的指针(void*)。

 2.函数功能:
    创建一个线程特定的数据键,该键对进程中的所有线程都可用,但该键与不同线程的私有数据地址相关联。
    创建新键时,每个线程都会将一个值绑定到该键。这些值特定于线程并且针对每个线程单独维护。所有线程最初都具有与该键关联的NULL值。
    若创建该键时指定了destructor()析构函数,则该线程退出时,
      若数据地址已被置为 非null值 则析构函数会被调用,它唯一的参数就是该数据地址。
      若传入的destructor()参数为 null值 ,则表明没有析构函数与键关联。
        ①线程调用pthread_exit()或线程执行返回 正常退出 时,析构函数会被调用。
        ②若线程调用exit()、_exit()、_Exit()、abort()或其他 非正常退出 时,不会调用析构函数。
    成功返回时,会将已分配的键存储在key指向的位置中。调用方必须确保对该键的存储和访问进行正确的同步。

3.错误代码:
    EAGAIN:key名称空间已经用完。
    ENOMEM:此进程中虚拟内存不足,无法创建新键。

pthread_key_delete ()——删除线程键
  1.函数功能:销毁现有线程特定数据键。由于键已无效,因此将释放与该键关联的所有内存。引用无效键将返回错误。
  该函数可在析构函数中调用,但不能调用析构函数。

 2.错误代码:
    EINVAL: key的值无效。

pthread_once()——动态包初始化
  1.函数功能:可在首次调用pthread_once时调用初始化例程。以后调用pthread_once()将不起作用。

  进程中的任何线程第一次调用pthread_once()时,使用给定的once_control,应该不带参数地调用init_routine。后续使用相同的once_control调用pthread_once()时,将不会调用init_例程。从pthread_once()返回时,init_routine应该已经完成。once_control参数应确定是否调用了相关的初始化例程。

 2.错误代码:
    EINVAL: once_controlinit_routineNULL。

pthread_getspecific()——获取线程私有数据地址:
 1.函数功能:获取调用线程的键绑定,并将该绑定存储在POINTER指向的位置中。(返回由KEY标识的线程特定的数据槽的当前值)

线程键的注意事项:
    ①若已经删除键,则调用pthread_setspecific()pthread_getspecific()引用该键时,生成结果将是不确定的
    ②调用删除函数之前必须释放所有线程特定资源。
    ③删除函数不会调用任何析构函数。
    ④反复调用pthread_key_create()pthread_key_delete()可能会产生问题。
    ⑤每个所需的键都只调用pthread_key_create()一次

pthread_setspecific ()——设置 线程特定数据
  1.函数功能:把键和线程私有数据关联起来。(将POINTER存储在由KEY标识的线程特定的数据槽中)

2.错误代码:
    ENOMEM:虚拟内存不足。
    EINVAL: key无效。

五、取消选项

pthread_setcancelstate()——设置取消状态
 1.函数功能:将调用线程的取消状态设置为state中给定的值。线程的前一个可取消状态会在oldstate指向的缓冲区中返回。

2.state值:
    PTHREAD_CANCEL_ENABLE:线程是可取消的。这是所有新线程的默认取消状态,包括初始线程。线程的可取消类型决定了可取消线程何时响应取消请求。
    PTHREAD_CANCEL_DISABLE:线程是不可取消的。如果收到一个取消请求,它会被阻塞,直到可取消性被启用。

pthread_setcanceltype()——设置取消类型
  1.函数功能:将调用线程的取消类型设置为type中给定的值。线程的前一个取消类型在oldtype指向的缓冲区中返回。

2.type值:
PTHREAD_CANCEL_DEFERRED
取消请求被延迟到下一个线程调用一个作为取消点的函数(参见pthreads(7))。这是所有新线程的默认取消类型,包括初始线程。
即使延迟取消,异步信号处理程序中的取消点仍然可以被操作,其效果就像异步取消一样。
PTHREAD_CANCEL_ASYNCHRONOUS:
线程可以在任何时候被取消。(通常,它会在收到取消请求后立即被取消,但系统不保证这一点。)
与进程中调用相同函数的其他线程相比,这些函数执行的set-and-get操作是原子的。

pthread_testcancel()——请求交付任何未决的取消请求
  调用pthread_testcancel时,如果有某个取消请求正处于未决状态,而且取消并没有置为无效,那么线程就会被取消。但是如果取消被置为无效时,pthread_testcancel调用就没有任何效果。
  这里所描述的默认取消类型也称为延迟取消。调用pthread_cancel以后,在线程到达取消点之前,并不会出现真正的取消。可以通过调用pthread_setcanceltype来修改取消类型。

 1.函数功能:在调用线程中创建一个取消点,以便执行不包含取消点的代码的线程将响应一个取消请求。

六、线程和信号

pthread_sigmask()——检查并更换屏蔽信号
  1.函数功能:与sigprocmask(2)类似,不同之处在于它在多线程程序中的使用是由POSIX.1显式指定的。

sigwait()——等待信号
 1.函数功能:将暂停调用线程的执行,直到信号集中指定的一个信号变为挂起状态。该函数接受信号(将其从挂起的信号列表中删除),并返回sig中的信号号。

pthread_kill()——向线程发送一个信号
 1.函数功能:将信号sig发送给线程,该线程与调用者处于同一个进程中。该信号被异步定向到线程。
    如果sig为0,则不发送信号,但仍然进行错误检查

七、线程和fork()

pthread_atfork()——注册叉处理程序
  1.函数功能:pthread_atfork()函数应该在调用fork()的线程的上下文中声明fork处理程序在fork()之前和之后被调用。prepare fork处理程序应该在fork()处理开始之前被调用。父进程fork()处理完成后,调用父进程的fork句柄。子fork处理程序应该在子进程中的fork()处理完成后被调用。如果这三个点中的一个或多个不需要处理,则相应的fork处理程序地址可以设置为NULL。
    调用pthread_atfork()的顺序非常重要。父和子fork处理程序的调用顺序应该是通过调用pthread_atfork()建立的。预备fork处理程序应该以相反的顺序调用。