[ English | 简体中文 ]
线程 API
openvela 提供 POSIX 兼容的线程(pthread)接口,支持线程创建、同步、属性管理等功能。
头文件:#include <pthread.h>
openvela 实现说明
openvela 的 pthread 实现基于 NuttX RTOS 内核,与标准 Linux 实现存在以下差异:
pthread_t即pid_t:在 openvela 中,线程 ID 的底层类型是pid_t(进程 ID),可以直接用于kill()等系统调用。- 无进程隔离:openvela 不支持 Linux 意义上的进程,所有线程运行在同一地址空间。
PTHREAD_PROCESS_SHARED属性可设置但行为与PTHREAD_PROCESS_PRIVATE相同。 - 竞争范围固定:仅支持
PTHREAD_SCOPE_SYSTEM,PTHREAD_SCOPE_PROCESS返回ENOTSUP。 fork()支持有限:pthread_atfork()接口存在但fork()在 RTOS 环境中可能不可用,主要用于 POSIX 兼容性。- 条件编译依赖:部分功能需要特定配置项:
CONFIG_SMP:CPU 亲和性接口(pthread_setaffinity_np等)CONFIG_PRIORITY_INHERITANCE:优先级继承协议(PTHREAD_PRIO_INHERIT)CONFIG_PRIORITY_PROTECT:优先级上限保护(PTHREAD_PRIO_PROTECT、prioceiling相关接口)CONFIG_RR_INTERVAL > 0:SCHED_RR调度策略CONFIG_SCHED_SPORADIC:SCHED_SPORADIC调度策略
线程创建与管理
pthread_create
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
pthread_startroutine_t start_routine, pthread_addr_t arg);
类型说明:
pthread_startroutine_t等价于void *(*)(void *),pthread_addr_t等价于void *,均为 NuttX 的类型别名。
创建一个新线程并使其可运行。新线程从 start_routine 函数开始执行,该函数接收 arg 作为唯一参数。线程属性对象 attr 指定了新线程的各种属性,如栈大小、调度策略、优先级等。
如果 attr 为 NULL,则使用默认属性创建线程。默认情况下,线程是可连接的(joinable),具有默认的栈大小和调度策略。
参数:
thread指向pthread_t类型的指针,用于存储新创建线程的 ID。成功时,线程 ID 会被写入此位置。attr指向线程属性对象的指针。如果为NULL,使用默认属性(栈大小为PTHREAD_STACK_DEFAULT,调度策略为SCHED_OTHER,可连接状态)。start_routine线程入口函数,函数签名为void *(*)(void *)。新线程将从此函数开始执行。arg传递给入口函数的参数。如果需要传递多个参数,可以传递结构体指针。
返回值:
成功时返回 0,失败时返回错误码:
EAGAIN系统资源不足,无法创建新线程,或达到了系统线程数限制。EINVALattr中的设置无效。EPERM没有权限设置指定的调度策略或参数。
注意:
- 新创建的线程与调用线程共享相同的地址空间、文件描述符和信号处理。
- 如果线程创建时指定了
PTHREAD_CREATE_DETACHED状态,线程终止后会自动释放资源,无需调用pthread_join()。 - 线程创建后立即可调度运行,不保证创建顺序就是执行顺序。
- 线程的返回值可以通过
pthread_join()获取,或通过pthread_exit()显式返回。 - 确保传递给线程的参数在线程执行期间保持有效,避免传递栈上的局部变量地址。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_exit
void pthread_exit(void *exit_value);
终止调用线程并返回一个值,该值可被其他调用 pthread_join() 等待此线程的线程获取。此函数不会返回到调用者。
调用 pthread_exit() 等效于从线程入口函数返回,但可以在线程调用的任何函数中调用。线程终止时,会执行以下清理操作:
- 调用通过
pthread_cleanup_push()注册的清理函数(按注册顺序的逆序)。 - 调用线程特定数据的析构函数(对于所有非
NULL的线程特定数据键)。 - 如果线程是可连接的,保留线程 ID 和返回值,直到其他线程调用
pthread_join()。 - 如果线程是分离的,立即释放所有资源。
参数:
exit_value线程返回值,这是一个无类型指针,可以传递任何数据的地址。等待此线程的pthread_join()调用可以获取此值。如果线程被取消,返回值为PTHREAD_CANCELED。
返回值:
此函数不返回。调用后,调用线程终止。
注意:
- 不要在
main()函数中调用pthread_exit(),这会终止主线程但不终止进程,可能导致其他线程成为孤儿。 - 如果线程已分离,
exit_value将被忽略,因为没有线程可以通过pthread_join()获取返回值。 - 线程终止时,不会自动关闭打开的文件描述符或释放分配的内存,这些资源由整个进程共享。
- 从线程入口函数返回隐式调用
pthread_exit(),返回值作为线程的退出值。 - 如果线程持有互斥锁,在调用
pthread_exit()前应释放,否则可能导致死锁。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_join
int pthread_join(pthread_t thread, pthread_addr_t *value);
类型说明:
pthread_addr_t等价于void *,为 NuttX 的类型别名。
阻塞调用线程,直到指定的线程 thread 终止。如果该线程已经终止,pthread_join() 立即返回。成功返回后,目标线程被"连接"(joined),其资源被回收。
每个可连接的线程只能被连接一次。尝试连接已被连接或分离的线程会导致未定义行为。线程不能连接自己,否则会导致死锁。
参数:
thread要等待的线程 ID,必须是可连接状态的线程。不能是分离状态的线程,也不能是已被连接过的线程。value指向指针的指针,用于接收线程的返回值。如果非NULL,目标线程的返回值(通过pthread_exit()或从入口函数返回)会被写入*value。如果线程被取消,*value设置为PTHREAD_CANCELED。如果不关心返回值,可以传递NULL。
返回值:
成功时返回 0,失败时返回错误码:
EDEADLK检测到死锁(如线程尝试连接自己),或thread指定另一个正在等待连接调用线程的线程。EINVALthread不是可连接的线程,或者已有其他线程正在等待连接该线程。ESRCH找不到 ID 为thread的线程。
注意:
pthread_join()会阻塞调用线程,直到目标线程终止。如果目标线程已经终止,调用立即返回。- 连接线程后,线程 ID 被回收,不应再使用。
- 如果多个线程同时尝试连接同一个线程,行为是未定义的。
- 不连接可连接的线程会导致资源泄漏(类似于内存泄漏),线程资源不会被回收。
- 对于不需要获取返回值的线程,建议在创建时设置为分离状态,或创建后调用
pthread_detach()。 - 在 openvela 中,线程 ID 实际上是进程 ID(
pid_t),可以用于其他系统调用。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_detach
int pthread_detach(pthread_t thread);
将指定线程标记为分离状态。分离状态的线程在终止时会自动释放所有资源,无需其他线程调用 pthread_join() 来回收。一旦线程被分离,就不能再被连接,线程的返回值也无法获取。
线程可以通过两种方式变为分离状态:
- 创建时在属性对象中设置
PTHREAD_CREATE_DETACHED。 - 创建后调用
pthread_detach()。
线程也可以分离自己,通过 pthread_detach(pthread_self())。
参数:
thread要分离的线程 ID。可以是其他线程的 ID,也可以是调用线程自己的 ID(通过pthread_self()获取)。
返回值:
成功时返回 0,失败时返回错误码:
EINVALthread不是可连接的线程(可能已经是分离状态)。ESRCH找不到 ID 为thread的线程。
注意:
- 分离线程后,不能再调用
pthread_join()等待该线程,否则会返回错误。 - 分离状态是不可逆的,一旦分离就无法再变回可连接状态。
- 对于不需要获取返回值或等待其完成的线程,应该设置为分离状态,以避免资源泄漏。
- 分离状态不影响线程的执行,只影响线程终止后的资源回收方式。
- 如果对已分离的线程再次调用
pthread_detach(),会返回EINVAL错误。 - 主线程可以是分离的,但这通常不是好的做法,因为主线程终止会导致整个进程终止。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_cancel
int pthread_cancel(pthread_t thread);
向指定线程发送取消请求。线程是否响应取消请求取决于其取消状态(由 pthread_setcancelstate() 设置)和取消类型(由 pthread_setcanceltype() 设置)。
如果取消请求成功传递,目标线程的取消状态和类型决定了何时以及如何处理取消:
- 如果取消状态为
PTHREAD_CANCEL_DISABLE,取消请求被挂起,直到取消状态变为PTHREAD_CANCEL_ENABLE。 - 如果取消状态为
PTHREAD_CANCEL_ENABLE,且取消类型为PTHREAD_CANCEL_DEFERRED,取消在下一个取消点发生。 - 如果取消类型为
PTHREAD_CANCEL_ASYNCHRONOUS,取消可能立即发生(但也可能延迟)。
参数:
thread要取消的线程 ID。不能取消自己(应使用pthread_exit())。
返回值:
成功时返回 0,失败时返回错误码:
ESRCH找不到 ID 为thread的线程。
注意:
pthread_cancel()只是发送取消请求,不会等待线程实际终止。- 被取消的线程的退出值为
PTHREAD_CANCELED。 - 异步取消(
PTHREAD_CANCEL_ASYNCHRONOUS)是危险的,应仅在特定情况下使用,因为线程可能在任意点被取消,可能导致资源泄漏或数据不一致。 - 延迟取消(
PTHREAD_CANCEL_DEFERRED,默认)更安全,线程只在取消点被取消,这些点包括pthread_testcancel()、pthread_join()、pthread_cond_wait()等阻塞调用。 - 取消线程时,会执行清理处理程序(通过
pthread_cleanup_push()注册)和线程特定数据析构函数。 - 如果线程持有锁或其他资源,应通过清理处理程序确保资源被正确释放。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_setcancelstate
int pthread_setcancelstate(int state, int *oldstate);
设置调用线程的取消状态。取消状态决定了线程是否可以被取消。
参数:
state新的取消状态。有效值为:PTHREAD_CANCEL_ENABLE启用取消(默认)。线程可以响应取消请求。PTHREAD_CANCEL_DISABLE禁用取消。取消请求会被挂起,直到取消状态变为启用。
oldstate如果非NULL,用于存储之前的取消状态。可以传递NULL如果不需要获取旧值。
返回值:
成功时返回 0,失败时返回错误码:
EINVALstate不是有效的取消状态值。
注意:
- 新创建的线程默认取消状态为
PTHREAD_CANCEL_ENABLE。 - 禁用取消不会丢弃挂起的取消请求,只是延迟其处理。
- 即使禁用取消,线程仍可以通过
pthread_exit()自行终止。 - 在执行关键代码段(如资源分配和初始化)时,应临时禁用取消,完成后再启用。
- 取消状态是线程局部的,每个线程有自己独立的取消状态。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_setcanceltype
int pthread_setcanceltype(int type, int *oldtype);
设置调用线程的取消类型。取消类型决定了线程如何响应取消请求。
参数:
type新的取消类型。有效值为:PTHREAD_CANCEL_DEFERRED延迟取消(默认)。取消请求在下一个取消点才会处理。取消点包括pthread_testcancel()、pthread_join()、pthread_cond_wait()、pthread_cond_timedwait()、sem_wait()等阻塞函数。PTHREAD_CANCEL_ASYNCHRONOUS异步取消。线程可以在任何时刻被取消(实际行为依赖于实现)。这种模式非常危险,应避免使用。
oldtype如果非NULL,用于存储之前的取消类型。可以传递NULL如果不需要获取旧值。
返回值:
成功时返回 0,失败时返回错误码:
EINVALtype不是有效的取消类型值。
注意:
- 新创建的线程默认取消类型为
PTHREAD_CANCEL_DEFERRED。 - 延迟取消是推荐的取消类型,因为它只在定义明确的取消点响应取消,确保线程处于已知状态。
- 异步取消可能在任意指令处中断线程,可能导致资源泄漏、数据损坏或未定义行为。只有确保线程代码是异步取消安全的,才应使用异步取消。
- 如果使用异步取消,线程不应调用非异步取消安全的函数,包括大多数库函数。
- 取消类型是线程局部的,每个线程有自己独立的取消类型。
- 即使设置了异步取消,实现也可能将其视为延迟取消。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_testcancel
void pthread_testcancel(void);
创建一个取消点。如果有挂起的取消请求且取消状态为启用,则线程将被取消并不返回。这是一种显式检查并响应取消请求的方式。
取消点是线程可以响应取消请求的位置。POSIX 定义了一些函数必须是取消点(如 pthread_join()、sem_wait() 等阻塞调用),而 pthread_testcancel() 允许在任意位置创建取消点。
参数:
无参数。
返回值:
如果没有挂起的取消请求,函数正常返回。如果有挂起的取消请求,函数不返回,线程被取消。
注意:
- 如果线程取消状态为
PTHREAD_CANCEL_DISABLE,pthread_testcancel()不起作用,直接返回。 - 此函数通常用于长时间运行的计算密集型代码中,以提供响应取消请求的机会。
- 应在适当的位置(如循环中)定期调用
pthread_testcancel(),以确保线程能够及时响应取消请求。 - 如果线程被取消,会执行清理处理程序和线程特定数据析构函数。
- 过于频繁地调用
pthread_testcancel()可能影响性能;应在逻辑上合理的位置调用。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_self
pthread_t pthread_self(void);
获取调用线程的线程 ID。线程 ID 在进程内唯一标识一个线程,可用于 pthread_join()、pthread_detach()、pthread_equal() 等函数。
在 openvela 中,pthread_t 实际上是 pid_t 类型,即线程 ID 与进程 ID 相同。
参数:
无参数。
返回值:
返回调用线程的线程 ID。此函数总是成功,不会失败。
注意:
- 线程 ID 在线程生命周期内保持不变。
- 线程 ID 在线程终止并被连接后可能被重用。
- 不要依赖线程 ID 的数值或顺序,它们是不透明的标识符。
- 可以用
pthread_self()获取的 ID 调用pthread_detach(pthread_self())来分离当前线程。 - 在 openvela 中,可以将线程 ID 用于系统调用,如信号发送等。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_equal
int pthread_equal(pthread_t t1, pthread_t t2);
比较两个线程 ID 是否相等。由于线程 ID 的内部表示可能是复杂的数据结构,POSIX 要求使用此函数而不是直接用 == 比较。
参数:
t1第一个线程 ID。t2第二个线程 ID。
返回值:
如果两个线程 ID 相等,返回非零值;否则返回 0。
注意:
- 在 openvela 中,
pthread_t是简单的整数类型(pid_t),可以直接用==比较,但为了可移植性,建议使用pthread_equal()。 - 终止的线程 ID 可能被重用,因此不应假设 ID 的唯一性跨越线程生命周期。
- 常用于判断某个线程 ID 是否是当前线程:
pthread_equal(thread_id, pthread_self())。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_yield
void pthread_yield(void);
主动让出处理器,允许其他线程运行。这是一个优化提示,实际行为取决于调度策略。
调用 pthread_yield() 后,调用线程被放置在其优先级队列的末尾,调度器选择下一个可运行的线程。如果没有其他同等或更高优先级的就绪线程,调用线程可能立即继续执行。
参数:
无参数。
返回值:
无返回值。
注意:
- 此函数是非标准的扩展接口,但在许多系统上可用(Linux、BSD 等)。
- 在 POSIX 标准中,应使用
sched_yield()替代。 - 适用于协作式多任务场景,线程主动让出 CPU 给其他线程。
- 不应依赖
pthread_yield()来解决同步问题,应使用适当的同步原语(如互斥锁、条件变量)。 - 过度使用
pthread_yield()可能导致性能下降,应仅在明确需要时使用。 - 在实时系统中,
pthread_yield()的行为取决于调度策略(FIFO、RR 等)。
POSIX 兼容性:兼容扩展接口(非 POSIX 标准,但广泛支持)。
pthread_once
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));
确保初始化函数 init_routine 在进程生命周期内只被调用一次,无论有多少线程调用 pthread_once()。这是一种线程安全的单次初始化机制,常用于全局资源的延迟初始化。
once_control 必须是静态或全局变量,并使用 PTHREAD_ONCE_INIT 初始化。多个线程可以同时调用 pthread_once(),但 init_routine 只会被执行一次,其他线程会阻塞等待直到初始化完成。
参数:
once_control控制变量,用于跟踪初始化状态。必须使用PTHREAD_ONCE_INIT初始化(如pthread_once_t once = PTHREAD_ONCE_INIT;)。init_routine初始化函数,无参数无返回值。此函数在整个进程生命周期内只会被调用一次。
返回值:
成功时返回 0,失败时返回错误码:
EINVALonce_control或init_routine为NULL。
注意:
pthread_once()是线程安全的,可以从多个线程同时调用。- 初始化函数应快速完成,避免阻塞其他等待初始化完成的线程。
- 如果初始化函数内部调用
pthread_once()使用相同的once_control,行为是未定义的(可能死锁)。 - 初始化函数不应调用
pthread_exit()或被取消,否则初始化被视为未完成,下次调用pthread_once()会再次执行初始化。 - 常用于单例模式、全局资源初始化等场景。
once_control变量不应被直接修改,只能通过pthread_once()操作。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_atfork
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
注册在 fork() 调用时执行的处理函数。这些函数用于处理多线程环境中 fork() 带来的问题,特别是锁状态的一致性。
当调用 fork() 时,处理函数按以下顺序执行:
- 在
fork()之前,在父进程中调用所有prepare函数(按注册顺序的逆序)。 fork()创建子进程。- 在子进程中调用所有
child函数(按注册顺序)。 - 在父进程中调用所有
parent函数(按注册顺序)。
参数:
prepare在fork()前在父进程中调用。通常用于获取所有锁,确保一致状态。可以为NULL。parent在fork()后在父进程中调用。通常用于释放prepare中获取的锁。可以为NULL。child在fork()后在子进程中调用。通常用于重新初始化锁状态和其他资源。可以为NULL。
返回值:
成功时返回 0,失败时返回错误码:
ENOMEM内存不足,无法分配记录处理函数所需的空间。
注意:
- 可以多次调用
pthread_atfork()注册多组处理函数。 prepare函数按注册顺序的逆序调用,parent和child函数按注册顺序调用。- 在多线程程序中使用
fork()是危险的,因为子进程只继承调用fork()的线程,其他线程在子进程中不存在,但它们持有的锁状态被继承,可能导致死锁。 pthread_atfork()处理函数应快速执行,避免调用可能阻塞或使用锁的复杂函数。- 在子进程中,只应调用异步信号安全的函数(如
exec()系列函数)。 - openvela 作为 RTOS,
fork()支持可能有限或不存在,此接口主要用于兼容性。
POSIX 兼容性:兼容 POSIX 同名接口。
线程属性
pthread_attr_init
int pthread_attr_init(pthread_attr_t *attr);
初始化线程属性对象为默认值。属性对象用于在创建线程时指定线程的各种属性,如栈大小、调度策略、优先级、分离状态等。
初始化后的属性对象包含以下默认值:
- 分离状态:
PTHREAD_CREATE_JOINABLE(可连接) - 栈大小:
PTHREAD_STACK_DEFAULT(系统默认) - 调度策略:
SCHED_OTHER(或系统默认策略) - 调度继承:
PTHREAD_INHERIT_SCHED(继承父线程) - 作用域:
PTHREAD_SCOPE_SYSTEM
参数:
attr指向要初始化的线程属性对象。
返回值:
成功时返回 0,失败时返回错误码:
ENOMEM内存不足,无法初始化属性对象。
注意:
- 属性对象初始化后,可以通过各种
pthread_attr_set*()函数修改具体属性。 - 同一个属性对象可以用于创建多个线程。
- 使用完毕后,应调用
pthread_attr_destroy()销毁属性对象,释放资源。 - 属性对象的修改不影响已创建的线程,只影响后续使用该属性对象创建的线程。
- 在 openvela 中,属性对象是简单的结构体,不涉及动态内存分配。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_destroy
int pthread_attr_destroy(pthread_attr_t *attr);
销毁线程属性对象,释放其占用的资源。销毁后的属性对象不能再使用,除非重新初始化。
参数:
attr指向要销毁的属性对象。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr不是有效的属性对象。
注意:
- 销毁属性对象不影响已使用该对象创建的线程。
- 销毁后的属性对象可以通过
pthread_attr_init()重新初始化并使用。 - 在 openvela 中,属性对象通常不涉及动态内存,此函数主要用于 POSIX 兼容性。
- 应始终配对调用
pthread_attr_init()和pthread_attr_destroy(),遵循资源管理的最佳实践。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_setdetachstate
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
设置线程属性对象中的分离状态。分离状态决定线程终止后资源的回收方式。
参数:
attr指向线程属性对象。不能为NULL。detachstate分离状态,有效值为:PTHREAD_CREATE_JOINABLE可连接(默认),需要其他线程调用pthread_join()回收资源。PTHREAD_CREATE_DETACHED分离状态,线程终止后自动释放资源。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL,或detachstate不是有效值。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_getdetachstate
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
获取线程属性对象中的分离状态。
参数:
attr指向线程属性对象。不能为NULL。detachstate指向整型变量,用于存储分离状态。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或detachstate为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_setstacksize
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
设置线程属性对象中的栈大小。
参数:
attr指向线程属性对象。不能为NULL。stacksize栈大小(字节)。不能小于PTHREAD_STACK_MIN。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL,或stacksize小于PTHREAD_STACK_MIN。
注意:
- 栈大小应根据线程的实际需求设置,过小可能导致栈溢出。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_getstacksize
int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);
获取线程属性对象中的栈大小。
参数:
attr指向线程属性对象。stacksize指向size_t变量,用于存储栈大小。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALstacksize为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_setstackaddr
int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr);
设置线程属性对象中的栈地址。允许应用程序为线程指定预分配的栈内存。
参数:
attr指向线程属性对象。不能为NULL。stackaddr栈内存的起始地址。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或stackaddr为NULL。
注意:
- 此接口已被 POSIX 标记为废弃(obsolete),建议使用
pthread_attr_setstack()替代,后者可同时设置栈地址和栈大小。 - 使用自定义栈时,应用程序负责栈内存的分配和释放。
- 栈内存必须在线程生命周期内保持有效。
POSIX 兼容性:兼容 POSIX 同名接口(已废弃)。
pthread_attr_getstackaddr
int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr);
获取线程属性对象中的栈地址。
参数:
attr指向线程属性对象。不能为NULL。stackaddr指向指针变量,用于存储栈地址。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或stackaddr为NULL。
注意:
- 此接口已被 POSIX 标记为废弃,建议使用
pthread_attr_getstack()替代。
POSIX 兼容性:兼容 POSIX 同名接口(已废弃)。
pthread_attr_setstack
int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
同时设置线程属性对象中的栈地址和栈大小。这是 pthread_attr_setstackaddr() 和 pthread_attr_setstacksize() 的组合替代接口。
参数:
attr指向线程属性对象。不能为NULL。stackaddr栈内存的起始地址。不能为NULL。stacksize栈大小(字节)。不能小于PTHREAD_STACK_MIN。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或stackaddr为NULL,或stacksize小于PTHREAD_STACK_MIN。
注意:
- 使用自定义栈时,应用程序负责栈内存的分配和释放,且内存必须在线程生命周期内有效。
- 栈大小应考虑线程的实际需求,包括局部变量、函数调用深度等。
- 在 openvela 中,
PTHREAD_STACK_MIN的值取决于系统配置。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_getstack
int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize);
同时获取线程属性对象中的栈地址和栈大小。
参数:
attr指向线程属性对象。不能为NULL。stackaddr指向指针变量,用于存储栈地址。不能为NULL。stacksize指向size_t变量,用于存储栈大小。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr、stackaddr或stacksize为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_setguardsize
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
设置线程属性对象中的栈保护区大小。保护区是栈末尾的一段不可访问内存,用于检测栈溢出。
参数:
attr指向线程属性对象。不能为NULL。guardsize保护区大小(字节)。设置为 0 表示禁用栈保护。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL。
注意:
- 如果使用
pthread_attr_setstack()指定了自定义栈,保护区设置可能被忽略。 - 实际保护区大小可能被系统向上取整到页大小的整数倍。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_getguardsize
int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize);
获取线程属性对象中的栈保护区大小。
参数:
attr指向线程属性对象。guardsize指向size_t变量,用于存储保护区大小。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALguardsize为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_setschedpolicy
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
设置线程属性对象中的调度策略。
参数:
attr指向线程属性对象。不能为NULL。policy调度策略,有效值为:SCHED_OTHER默认调度策略。SCHED_FIFO先进先出实时调度。SCHED_RR时间片轮转实时调度(需CONFIG_RR_INTERVAL > 0)。SCHED_SPORADIC偶发调度(需CONFIG_SCHED_SPORADIC)。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL,或policy不是有效的调度策略。
注意:
SCHED_RR和SCHED_SPORADIC的可用性取决于系统配置。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_getschedpolicy
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
获取线程属性对象中的调度策略。
参数:
attr指向线程属性对象。不能为NULL。policy指向整型变量,用于存储调度策略。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或policy为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_setschedparam
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
设置线程属性对象中的调度参数。
参数:
attr指向线程属性对象。不能为NULL。param指向调度参数结构体。不能为NULL。主要字段:sched_priority线程优先级。sched_ss_low_priority偶发调度低优先级(需CONFIG_SCHED_SPORADIC)。sched_ss_repl_period偶发调度补充周期。sched_ss_init_budget偶发调度初始预算。sched_ss_max_repl偶发调度最大补充次数。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或param为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_getschedparam
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
获取线程属性对象中的调度参数。
参数:
attr指向线程属性对象。不能为NULL。param指向调度参数结构体,用于存储结果。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或param为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_setinheritsched
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);
设置线程属性对象中的调度继承方式。决定新线程是继承创建者的调度属性,还是使用属性对象中显式指定的值。
参数:
attr指向线程属性对象。不能为NULL。inheritsched继承方式,有效值为:PTHREAD_INHERIT_SCHED继承创建线程的调度策略和参数(默认)。PTHREAD_EXPLICIT_SCHED使用属性对象中设置的调度策略和参数。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL,或inheritsched不是有效值。
注意:
- 如果设置为
PTHREAD_EXPLICIT_SCHED,需要同时通过pthread_attr_setschedpolicy()和pthread_attr_setschedparam()设置调度策略和参数。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_getinheritsched
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched);
获取线程属性对象中的调度继承方式。
参数:
attr指向线程属性对象。不能为NULL。inheritsched指向整型变量,用于存储继承方式。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或inheritsched为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_setscope
int pthread_attr_setscope(pthread_attr_t *attr, int scope);
设置线程属性对象中的竞争范围。竞争范围定义了线程与哪些线程竞争 CPU 等资源。
参数:
attr指向线程属性对象。scope竞争范围,有效值为:PTHREAD_SCOPE_SYSTEM系统级竞争,线程与系统中所有线程竞争资源。PTHREAD_SCOPE_PROCESS进程级竞争,线程仅与同一进程内的线程竞争。
返回值:
成功时返回 0,失败时返回错误码:
EINVALscope不是有效值。ENOTSUP不支持请求的竞争范围。在 openvela 中,PTHREAD_SCOPE_PROCESS不受支持。
注意:
- openvela 仅支持
PTHREAD_SCOPE_SYSTEM,这也是默认值。传入PTHREAD_SCOPE_PROCESS会返回ENOTSUP。 - 在 RTOS 环境中,所有线程天然在系统级别竞争资源。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_getscope
int pthread_attr_getscope(const pthread_attr_t *attr, int *scope);
获取线程属性对象中的竞争范围。
参数:
attr指向线程属性对象。scope指向整型变量,用于存储竞争范围。
返回值:
成功时返回 0。
注意:
- 在 openvela 中,始终返回
PTHREAD_SCOPE_SYSTEM。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_attr_setaffinity_np
int pthread_attr_setaffinity_np(pthread_attr_t *attr, size_t cpusetsize, const cpu_set_t *cpuset);
设置线程属性对象中的 CPU 亲和性掩码。使用该属性创建的线程将被限制在指定的 CPU 集合上运行。
参数:
attr指向线程属性对象。不能为NULL。cpusetsizecpuset缓冲区的大小(字节),必须为sizeof(cpu_set_t)。cpuset指向 CPU 集合,指定线程可运行的 CPU。不能为NULL,且集合不能为空。
返回值:
成功时返回 0。
注意:
- 仅在启用 SMP(
CONFIG_SMP)时可用。 - 与
pthread_setaffinity_np()不同,此函数设置的是属性对象中的亲和性,在pthread_create()时生效。 - 使用
CPU_ZERO()、CPU_SET()等宏操作cpu_set_t。
POSIX 兼容性:兼容 Linux 扩展接口(非 POSIX 标准)。
pthread_attr_getaffinity_np
int pthread_attr_getaffinity_np(const pthread_attr_t *attr, size_t cpusetsize, cpu_set_t *cpuset);
获取线程属性对象中的 CPU 亲和性掩码。
参数:
attr指向线程属性对象。不能为NULL。cpusetsizecpuset缓冲区的大小(字节),必须为sizeof(cpu_set_t)。cpuset指向 CPU 集合,用于存储亲和性掩码。不能为NULL。
返回值:
成功时返回 0。
注意:
- 仅在启用 SMP(
CONFIG_SMP)时可用。
POSIX 兼容性:兼容 Linux 扩展接口(非 POSIX 标准)。
线程调度
pthread_getschedparam
int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param);
获取指定线程的调度策略和调度参数。
参数:
thread线程 ID。policy指向整型变量,用于存储调度策略。不能为NULL。param指向调度参数结构体,用于存储结果。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALpolicy或param为NULL。ESRCH找不到指定线程。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_setschedparam
int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param);
设置指定线程的调度策略和调度参数。
参数:
thread线程 ID。policy调度策略:SCHED_FIFO、SCHED_RR、SCHED_OTHER或SCHED_SPORADIC。param指向调度参数结构体。
返回值:
成功时返回 0,失败时返回错误码:
EINVAL参数无效。ESRCH找不到指定线程。EPERM没有权限修改调度参数。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_setschedprio
int pthread_setschedprio(pthread_t thread, int prio);
设置指定线程的优先级,不改变调度策略。
参数:
thread线程 ID。prio新的优先级值。
返回值:
成功时返回 0,失败时返回错误码:
EINVAL优先级值无效。ESRCH找不到指定线程。
注意:
- 此函数仅修改优先级,保留当前调度策略和其他调度参数(如偶发调度参数)不变。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_setaffinity_np
int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);
设置线程的 CPU 亲和性掩码。如果线程当前未运行在 cpuset 指定的 CPU 上,将被迁移到其中一个 CPU。
参数:
thread线程 ID。cpusetsizecpuset缓冲区的大小(字节),通常为sizeof(cpu_set_t)。cpuset指向 CPU 集合,指定线程可以运行的 CPU。
返回值:
成功时返回 0,失败时返回错误码:
EINVAL参数无效。ESRCH找不到指定线程。
注意:
- 仅在启用 SMP(
CONFIG_SMP)时可用。 - 使用
CPU_ZERO()、CPU_SET()等宏操作cpu_set_t。
POSIX 兼容性:兼容 Linux 扩展接口(非 POSIX 标准)。
pthread_getaffinity_np
int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset);
获取线程的 CPU 亲和性掩码。
参数:
thread线程 ID。cpusetsizecpuset缓冲区的大小(字节),通常为sizeof(cpu_set_t)。cpuset指向 CPU 集合,用于存储线程的亲和性掩码。
返回值:
成功时返回 0,失败时返回错误码:
EINVAL参数无效。ESRCH找不到指定线程。
注意:
- 仅在启用 SMP(
CONFIG_SMP)时可用。
POSIX 兼容性:兼容 Linux 扩展接口(非 POSIX 标准)。
pthread_setconcurrency
int pthread_setconcurrency(int new_level);
设置并发级别提示。此函数向系统提示应用程序期望的并发线程数,系统可以据此优化线程调度。
参数:
new_level期望的并发级别。值为 0 表示由系统自行决定。不能为负数。
返回值:
成功时返回 0,失败时返回错误码:
EINVALnew_level为负数。
注意:
- 此函数仅为提示,系统不保证实际并发级别与设置值一致。
- 在 openvela 中,此值存储在全局变量中,不影响实际调度行为。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_getconcurrency
int pthread_getconcurrency(void);
获取当前的并发级别提示值。
参数:
无参数。
返回值:
返回之前通过 pthread_setconcurrency() 设置的值。如果从未设置,返回 0。
POSIX 兼容性:兼容 POSIX 同名接口。
互斥锁
pthread_mutex_init
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
初始化互斥锁。互斥锁用于保护共享资源,确保同一时刻只有一个线程可以访问被保护的临界区。
如果 attr 为 NULL,使用默认属性:类型为 PTHREAD_MUTEX_NORMAL,不支持优先级继承或保护协议,进程私有。
互斥锁也可以使用 PTHREAD_MUTEX_INITIALIZER 静态初始化:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
参数:
mutex指向要初始化的互斥锁对象。attr指向互斥锁属性对象。如果为NULL,使用默认属性。属性包括互斥锁类型(normal、recursive、errorcheck)、优先级协议、健壮性等。
返回值:
成功时返回 0,失败时返回错误码:
EAGAIN系统资源不足,无法初始化互斥锁。ENOMEM内存不足。EPERM调用者没有权限。EINVALattr中的属性值无效。
注意:
- 初始化后的互斥锁处于未锁定状态。
- 不要重复初始化已初始化的互斥锁,这会导致未定义行为。
- 使用完毕后应调用
pthread_mutex_destroy()销毁互斥锁。 - 静态初始化的互斥锁不需要显式销毁。
- 互斥锁类型影响重复加锁和错误检测行为:
PTHREAD_MUTEX_NORMAL:不检测死锁,重复加锁会导致死锁。PTHREAD_MUTEX_ERRORCHECK:检测死锁和错误,性能略低。PTHREAD_MUTEX_RECURSIVE:允许同一线程多次加锁,需要相同次数的解锁。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutex_destroy
int pthread_mutex_destroy(pthread_mutex_t *mutex);
销毁互斥锁,释放其占用的资源。
参数:
mutex指向要销毁的互斥锁。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALmutex为NULL或未正确初始化。EBUSY互斥锁当前被锁定,无法销毁。
注意:
- 不能销毁正在被使用(锁定)的互斥锁。
- 销毁后的互斥锁不能再使用,除非重新初始化。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutex_lock
int pthread_mutex_lock(pthread_mutex_t *mutex);
锁定互斥锁。如果互斥锁当前未被锁定,调用线程获得锁并立即返回。如果互斥锁已被其他线程锁定,调用线程阻塞等待,直到锁可用。
具体行为取决于互斥锁类型:
- NORMAL(默认):如果锁已被当前线程持有,再次加锁会导致死锁。
- ERRORCHECK:如果锁已被当前线程持有,返回
EDEADLK错误。 - RECURSIVE:如果锁已被当前线程持有,递增锁计数,需要相同次数的解锁。
参数:
mutex指向要锁定的互斥锁。
返回值:
成功时返回 0,失败时返回错误码:
EDEADLK互斥锁类型为PTHREAD_MUTEX_ERRORCHECK,且当前线程已持有该锁(死锁检测)。EINVAL互斥锁未正确初始化。EOWNERDEAD互斥锁是健壮互斥锁,前一个持有者终止时未释放锁。调用者现在拥有该锁,应调用pthread_mutex_consistent()使其一致,或解锁并不再使用。ENOTRECOVERABLE健壮互斥锁处于不可恢复状态,无法再使用。
注意:
- 持有锁的线程应尽快释放锁,避免其他线程长时间等待。
- 避免在持有锁时调用可能阻塞的函数(如 I/O 操作),这可能导致性能问题。
- 避免嵌套锁定多个互斥锁,这可能导致死锁。如果必须,应保持固定的加锁顺序。
- 锁定互斥锁后,应使用
try-finally模式或清理处理程序确保锁始终被释放。 - 如果线程被取消,应通过清理处理程序(
pthread_cleanup_push/pop)确保锁被释放。 - 优先级反转问题:如果启用优先级继承协议,低优先级线程持有锁时,其优先级临时提升到等待线程的最高优先级。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutex_trylock
int pthread_mutex_trylock(pthread_mutex_t *mutex);
尝试锁定互斥锁(非阻塞)。如果互斥锁当前可用,函数获得锁并立即返回成功。如果互斥锁已被锁定,函数立即返回 EBUSY,不会阻塞等待。
这是 pthread_mutex_lock() 的非阻塞版本,适用于不希望等待锁的场景,如轮询、避免死锁等。
参数:
mutex指向要尝试锁定的互斥锁。
返回值:
成功时返回 0,失败时返回错误码:
EBUSY互斥锁已被锁定,无法获取。这不是真正的错误,只是表示锁当前不可用。EINVAL互斥锁未正确初始化。EDEADLK互斥锁类型为PTHREAD_MUTEX_ERRORCHECK,且当前线程已持有该锁。EOWNERDEAD健壮互斥锁的前一个持有者终止时未释放锁。ENOTRECOVERABLE健壮互斥锁处于不可恢复状态。
注意:
- 如果返回
EBUSY,调用者可以选择稍后重试或执行其他操作。 - 对于递归互斥锁,如果当前线程已持有锁,
pthread_mutex_trylock()会成功并递增锁计数。 - 常用于避免死锁的场景:尝试获取多个锁时,如果无法获取某个锁,可以释放已持有的锁并重试。
- 不应在循环中持续调用
pthread_mutex_trylock()(忙等待),这会浪费 CPU 资源。 - 适用于实现非阻塞算法或超时机制。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutex_timedlock
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime);
带超时的锁定互斥锁。如果互斥锁不能立即获取,阻塞等待直到锁可用或超时。
参数:
mutex指向要锁定的互斥锁。不能为NULL。abstime绝对超时时间(基于CLOCK_REALTIME)。
返回值:
成功时返回 0,失败时返回错误码:
ETIMEDOUT在超时时间内未能获取锁。EINVALmutex为NULL或未正确初始化。EDEADLK互斥锁类型为PTHREAD_MUTEX_ERRORCHECK,且当前线程已持有该锁。
注意:
- 对于递归互斥锁,如果当前线程已持有锁,会成功并递增锁计数,不受超时影响。
- 超时时间是绝对时间,不是相对时间。应基于
clock_gettime(CLOCK_REALTIME, ...)计算。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutex_unlock
int pthread_mutex_unlock(pthread_mutex_t *mutex);
解锁互斥锁,使其可供其他等待的线程获取。只有持有锁的线程才能解锁,否则行为取决于互斥锁类型。
对于递归互斥锁,每次 pthread_mutex_unlock() 调用递减锁计数,当计数降到零时锁才真正被释放。
参数:
mutex指向要解锁的互斥锁。
返回值:
成功时返回 0,失败时返回错误码:
EPERM当前线程不拥有该互斥锁。对于PTHREAD_MUTEX_ERRORCHECK类型,尝试解锁未持有的锁会返回此错误。对于PTHREAD_MUTEX_NORMAL类型,这是未定义行为。EINVAL互斥锁未正确初始化或已被销毁。
注意:
- 必须由锁定互斥锁的同一线程解锁,不能由其他线程代为解锁。
- 解锁未锁定的互斥锁是未定义行为(对于 NORMAL 类型)或返回错误(对于 ERRORCHECK 类型)。
- 解锁互斥锁后,如果有线程正在等待该锁,其中一个等待线程会被唤醒并获得锁。具体哪个线程被唤醒取决于调度策略。
- 在持有锁期间发生异常或取消时,应确保锁被释放,通过清理处理程序或异常处理机制。
- 解锁操作应尽可能快,避免在锁保护的临界区外调用 unlock。
- 对于优先级继承互斥锁,解锁时会恢复线程的原始优先级。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutex_consistent
int pthread_mutex_consistent(pthread_mutex_t *mutex);
将健壮互斥锁标记为一致状态。当健壮互斥锁的前一个持有者终止时未释放锁,pthread_mutex_lock() 会返回 EOWNERDEAD,此时新的持有者应调用此函数使互斥锁恢复一致。
参数:
mutex指向处于不一致状态的健壮互斥锁。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALmutex为NULL,或互斥锁不是健壮互斥锁,或不处于不一致状态。
注意:
- 需要互斥锁属性中设置了
PTHREAD_MUTEX_ROBUST。 - 如果不调用此函数而直接解锁,互斥锁将进入不可恢复状态,后续
pthread_mutex_lock()会返回ENOTRECOVERABLE。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutex_setprioceiling
int pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int prioceiling, int *old_ceiling);
动态修改互斥锁的优先级上限。此函数会先锁定互斥锁,修改优先级上限后再解锁,确保操作的原子性。
参数:
mutex指向互斥锁。prioceiling新的优先级上限值。old_ceiling如果非NULL,用于存储之前的优先级上限值。
返回值:
成功时返回 0,失败时返回错误码:
EINVAL参数无效,或未启用CONFIG_PRIORITY_PROTECT。EPERM无法锁定互斥锁。
注意:
- 需要启用
CONFIG_PRIORITY_PROTECT配置项。未启用时始终返回EINVAL。 - 互斥锁的协议必须为
PTHREAD_PRIO_PROTECT才有意义。 - 此函数内部会执行 lock/unlock 操作,调用时不应持有该互斥锁。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutex_getprioceiling
int pthread_mutex_getprioceiling(const pthread_mutex_t *mutex, int *prioceiling);
获取互斥锁当前的优先级上限。
参数:
mutex指向互斥锁。prioceiling指向整型变量,用于存储优先级上限值。
返回值:
成功时返回 0,失败时返回错误码:
EINVAL参数无效,或未启用CONFIG_PRIORITY_PROTECT。
注意:
- 需要启用
CONFIG_PRIORITY_PROTECT配置项。
POSIX 兼容性:兼容 POSIX 同名接口。
互斥锁属性
pthread_mutexattr_init
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
初始化互斥锁属性对象为默认值。默认属性:类型 PTHREAD_MUTEX_NORMAL,协议 PTHREAD_PRIO_NONE,进程私有,非健壮。
参数:
attr指向要初始化的互斥锁属性对象。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutexattr_destroy
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
销毁互斥锁属性对象。
参数:
attr指向要销毁的互斥锁属性对象。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutexattr_settype
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
设置互斥锁类型。类型决定了重复加锁和错误检测的行为。
参数:
attr指向互斥锁属性对象。不能为NULL。type互斥锁类型:PTHREAD_MUTEX_NORMAL不检测死锁,重复加锁导致死锁(默认)。PTHREAD_MUTEX_ERRORCHECK检测死锁,重复加锁返回EDEADLK。PTHREAD_MUTEX_RECURSIVE允许同一线程多次加锁,需相同次数解锁。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL,或type不是有效值。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutexattr_gettype
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type);
获取互斥锁类型。
参数:
attr指向互斥锁属性对象。不能为NULL。type指向整型变量,用于存储互斥锁类型。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或type为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutexattr_setpshared
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);
设置互斥锁属性对象中的进程共享属性。
参数:
attr指向互斥锁属性对象。不能为NULL。pshared进程共享属性值:PTHREAD_PROCESS_PRIVATE(0)进程私有(默认)。PTHREAD_PROCESS_SHARED(1)进程间共享。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL,或pshared不是 0 或 1。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutexattr_getpshared
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared);
获取互斥锁属性对象中的进程共享属性。
参数:
attr指向互斥锁属性对象。不能为NULL。pshared指向整型变量,用于存储进程共享属性值。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或pshared为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutexattr_setprotocol
int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol);
设置互斥锁优先级协议。协议决定了持有锁的线程如何处理优先级反转问题。
参数:
attr指向互斥锁属性对象。不能为NULL。protocol优先级协议:PTHREAD_PRIO_NONE不使用优先级协议(默认)。PTHREAD_PRIO_INHERIT优先级继承,持有锁的低优先级线程临时提升到等待线程的最高优先级(需CONFIG_PRIORITY_INHERITANCE)。PTHREAD_PRIO_PROTECT优先级上限保护(需CONFIG_PRIORITY_PROTECT)。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL,或protocol不是有效值或不受支持。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutexattr_getprotocol
int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol);
获取互斥锁优先级协议。
参数:
attr指向互斥锁属性对象。不能为NULL。protocol指向整型变量,用于存储协议值。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或protocol为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutexattr_setrobust
int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, int robust);
设置互斥锁健壮性属性。健壮互斥锁在持有者异常终止时不会永久锁死。
参数:
attr指向互斥锁属性对象。不能为NULL。robust健壮性属性:PTHREAD_MUTEX_STALLED非健壮(默认),持有者终止后锁永久不可用。PTHREAD_MUTEX_ROBUST健壮,持有者终止后下一个加锁者收到EOWNERDEAD,可通过pthread_mutex_consistent()恢复。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL,或robust不是有效值。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutexattr_getrobust
int pthread_mutexattr_getrobust(const pthread_mutexattr_t *attr, int *robust);
获取互斥锁健壮性属性。
参数:
attr指向互斥锁属性对象。不能为NULL。robust指向整型变量,用于存储健壮性属性。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或robust为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutexattr_setprioceiling
int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling);
设置互斥锁属性对象中的优先级上限。当互斥锁协议为 PTHREAD_PRIO_PROTECT 时,持有锁的线程优先级会被提升到此上限值,以避免优先级反转。
参数:
attr指向互斥锁属性对象。不能为NULL。prioceiling优先级上限值,必须在sched_get_priority_min(SCHED_FIFO)和sched_get_priority_max(SCHED_FIFO)之间。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL,或prioceiling超出有效优先级范围。
注意:
- 需要启用
CONFIG_PRIORITY_PROTECT配置项。未启用时,此函数始终返回EINVAL。 - 应与
pthread_mutexattr_setprotocol(attr, PTHREAD_PRIO_PROTECT)配合使用。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_mutexattr_getprioceiling
int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *prioceiling);
获取互斥锁属性对象中的优先级上限。
参数:
attr指向互斥锁属性对象。不能为NULL。prioceiling指向整型变量,用于存储优先级上限值。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或prioceiling为NULL,或未启用CONFIG_PRIORITY_PROTECT。
POSIX 兼容性:兼容 POSIX 同名接口。
条件变量
pthread_cond_init
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
初始化条件变量。也可使用 PTHREAD_COND_INITIALIZER 静态初始化。
参数:
cond指向要初始化的条件变量。不能为NULL。attr条件变量属性。如果为NULL,使用默认属性(CLOCK_REALTIME,进程私有)。
返回值:
成功时返回 0,失败时返回错误码:
EINVALcond为NULL。ENOMEM内存不足。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_cond_destroy
int pthread_cond_destroy(pthread_cond_t *cond);
销毁条件变量。
参数:
cond指向要销毁的条件变量。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALcond为NULL或未正确初始化。EBUSY有线程正在等待该条件变量。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_cond_wait
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
等待条件变量被通知。此函数原子性地释放互斥锁并阻塞在条件变量上。当条件变量被 pthread_cond_signal() 或 pthread_cond_broadcast() 通知时,线程被唤醒,重新获取互斥锁,然后返回。
条件变量通常用于实现生产者-消费者模式或其他需要线程间协调的场景。典型用法:
pthread_mutex_lock(&mutex);
while (!condition) {
pthread_cond_wait(&cond, &mutex);
}
// 条件满足,处理数据
pthread_mutex_unlock(&mutex);
参数:
cond指向条件变量。mutex指向关联的互斥锁。调用前必须已被当前线程锁定。
返回值:
成功时返回 0,失败时返回错误码:
EINVALcond或mutex未正确初始化,或使用了不同的互斥锁。EPERM调用线程未持有互斥锁。
注意:
- 调用前必须持有关联的互斥锁,否则行为未定义。
- 函数返回时,互斥锁已重新被锁定,即使发生错误。
- 由于虚假唤醒的可能性,必须在循环中检查条件:
while (!condition) pthread_cond_wait(...)。虚假唤醒是指线程在没有信号通知的情况下被唤醒。 - 条件变量本身不保存状态,它只是一个同步原语。实际条件(布尔表达式)由应用程序维护,通常通过共享变量表示。
- 等待时互斥锁被原子性地释放,避免了释放锁和阻塞之间的竞态条件。
- 如果线程被取消,互斥锁会被重新锁定,然后清理处理程序被调用。应在清理处理程序中释放锁。
- 多个线程可以同时等待同一个条件变量。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_cond_timedwait
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *abstime);
带超时的等待条件变量。行为与 pthread_cond_wait() 相同,但在超时后自动返回。
参数:
cond指向条件变量。mutex指向关联的互斥锁,调用前必须已锁定。abstime绝对超时时间。时钟源取决于条件变量属性中的时钟设置(默认CLOCK_REALTIME)。
返回值:
成功时返回 0,失败时返回错误码:
ETIMEDOUT在超时时间内未收到通知。EINVAL参数无效。
注意:
- 即使超时返回,互斥锁也会被重新锁定。
- 仍需在循环中检查条件,因为可能存在虚假唤醒。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_cond_clockwait
int pthread_cond_clockwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
clockid_t clockid, const struct timespec *abstime);
使用指定时钟等待条件变量。允许在等待时直接指定时钟源,而不依赖属性对象中的设置。
参数:
cond指向条件变量。mutex指向关联的互斥锁,调用前必须已锁定。clockid时钟 ID,如CLOCK_REALTIME或CLOCK_MONOTONIC。abstime基于指定时钟的绝对超时时间。
返回值:
成功时返回 0,失败时返回错误码:
ETIMEDOUT在超时时间内未收到通知。EINVAL参数无效。
POSIX 兼容性:兼容扩展接口。
pthread_cond_signal
int pthread_cond_signal(pthread_cond_t *cond);
唤醒至少一个正在等待条件变量的线程。如果有多个线程在等待,调度策略决定哪个线程被唤醒。如果没有线程在等待,此调用不起作用(信号丢失)。
与 pthread_cond_broadcast() 不同,pthread_cond_signal() 只唤醒一个线程,适用于只有一个线程能够处理条件的场景,可以避免不必要的线程唤醒和上下文切换。
参数:
cond指向要通知的条件变量。
返回值:
成功时返回 0,失败时返回错误码:
EINVALcond未正确初始化。
注意:
- 调用
pthread_cond_signal()时不需要持有关联的互斥锁,但通常建议在持有锁时调用,以避免竞态条件。 - 被唤醒的线程不会立即执行,它会先尝试重新获取互斥锁。因此在调用 signal 后立即释放锁是一个好的做法。
- 如果在修改条件后不持有锁就调用 signal,可能导致"唤醒丢失"问题:等待线程可能在检查条件和调用 wait 之间被抢占。
- 典型模式:
pthread_mutex_lock(&mutex); // 修改共享状态,使条件成立 condition = true; pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); - 如果条件可能满足多个等待线程的需求,应使用
pthread_cond_broadcast()。 - POSIX 不保证信号的公平性,可能出现线程饥饿。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_cond_broadcast
int pthread_cond_broadcast(pthread_cond_t *cond);
唤醒所有正在等待条件变量的线程。所有等待线程被唤醒后,会竞争重新获取关联的互斥锁。如果没有线程在等待,此调用不起作用。
与 pthread_cond_signal() 不同,broadcast 唤醒所有等待线程,适用于条件变化可能影响多个线程的场景,或者不确定哪个线程应该被唤醒时。
参数:
cond指向要广播的条件变量。
返回值:
成功时返回 0,失败时返回错误码:
EINVALcond未正确初始化。
注意:
- 类似
pthread_cond_signal(),调用时通常应持有关联的互斥锁。 - 所有被唤醒的线程会串行竞争互斥锁,一次只有一个线程能获得锁并继续执行。
- 使用 broadcast 可能导致"惊群效应"(thundering herd):多个线程被唤醒但只有少数能真正处理条件,其他线程发现条件不满足后又回到等待状态,造成不必要的上下文切换。
- 适用场景:
- 条件变化影响所有等待线程(如资源状态变化、系统关闭信号)
- 不确定哪个线程应该处理条件
- 需要所有线程重新评估其等待条件
- 典型模式:
pthread_mutex_lock(&mutex); // 修改影响所有等待线程的共享状态 shutdown = true; pthread_cond_broadcast(&cond); pthread_mutex_unlock(&mutex); - 如果只需要唤醒一个线程,优先使用
pthread_cond_signal()以提高效率。
POSIX 兼容性:兼容 POSIX 同名接口。
条件变量属性
pthread_condattr_init
int pthread_condattr_init(pthread_condattr_t *attr);
初始化条件变量属性对象为默认值。初始化后的属性对象包含以下默认值:
- 进程共享属性:
PTHREAD_PROCESS_PRIVATE(进程私有) - 时钟属性:
CLOCK_REALTIME(系统实时时钟)
属性对象用于在调用 pthread_cond_init() 时指定条件变量的行为特性。同一个属性对象可以用于初始化多个条件变量。
参数:
attr指向要初始化的条件变量属性对象。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL。
注意:
- 使用完毕后应调用
pthread_condattr_destroy()销毁属性对象。 - 属性对象的修改不影响已使用该对象创建的条件变量。
- 如果需要使用
CLOCK_MONOTONIC作为超时时钟(避免系统时间调整的影响),应在初始化后调用pthread_condattr_setclock()修改时钟属性。 - 在 openvela 中,属性对象是简单的结构体(包含
pshared和clockid两个字段),不涉及动态内存分配。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_condattr_destroy
int pthread_condattr_destroy(pthread_condattr_t *attr);
销毁条件变量属性对象,释放其占用的资源。销毁后的属性对象不能再使用,除非重新调用 pthread_condattr_init() 初始化。
参数:
attr指向要销毁的条件变量属性对象。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL或不是有效的属性对象。
注意:
- 销毁属性对象不影响已使用该对象创建的条件变量。
- 在 openvela 中,属性对象不涉及动态内存分配,此函数主要用于 POSIX 兼容性。
- 应始终配对调用
pthread_condattr_init()和pthread_condattr_destroy()。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_condattr_getpshared
int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *pshared);
获取条件变量属性对象中的进程共享属性。进程共享属性决定了条件变量是否可以被多个进程中的线程访问。
参数:
attr指向条件变量属性对象。不能为NULL。pshared指向整型变量的指针,用于存储当前的进程共享属性值。不能为NULL。返回值为以下之一:PTHREAD_PROCESS_PRIVATE条件变量只能被同一进程内的线程使用(默认值)。PTHREAD_PROCESS_SHARED条件变量可以被多个进程中的线程使用,前提是条件变量分配在共享内存中。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或pshared为NULL。
注意:
- 在 openvela 中,由于 RTOS 的内存模型,
PTHREAD_PROCESS_SHARED的行为可能与 Linux 等系统不同。 - 默认值为
PTHREAD_PROCESS_PRIVATE。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_condattr_setpshared
int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared);
设置条件变量属性对象中的进程共享属性。该属性决定条件变量是否可以被不同进程中的线程操作。
如果设置为 PTHREAD_PROCESS_SHARED,任何能够访问条件变量所在内存的线程都可以操作该条件变量。如果设置为 PTHREAD_PROCESS_PRIVATE,只有与初始化条件变量的线程在同一进程内的线程才能操作。不同进程的线程尝试操作私有条件变量的行为是未定义的。
参数:
attr指向条件变量属性对象。不能为NULL。pshared进程共享属性值,必须为以下之一:PTHREAD_PROCESS_PRIVATE进程私有(默认)。PTHREAD_PROCESS_SHARED进程间共享。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL,或pshared不是PTHREAD_PROCESS_SHARED或PTHREAD_PROCESS_PRIVATE。
注意:
- 使用
PTHREAD_PROCESS_SHARED时,条件变量必须分配在所有相关进程都能访问的共享内存区域中。 - 与条件变量关联的互斥锁也应设置为进程共享。
- 修改属性对象不影响已创建的条件变量。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_condattr_getclock
int pthread_condattr_getclock(const pthread_condattr_t *attr, clockid_t *clock_id);
获取条件变量属性对象中的时钟属性。时钟属性决定了 pthread_cond_timedwait() 使用哪个时钟来计算超时时间。
参数:
attr指向条件变量属性对象。不能为NULL。clock_id指向clockid_t变量的指针,用于存储当前的时钟属性值。返回值为以下之一:CLOCK_REALTIME系统实时时钟(默认值)。受系统时间调整(如 NTP)影响。CLOCK_MONOTONIC单调递增时钟。不受系统时间调整影响。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL。
注意:
- 默认时钟为
CLOCK_REALTIME。 - 如果应用程序对超时精度有要求,或系统时间可能被调整,建议使用
CLOCK_MONOTONIC。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_condattr_setclock
int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id);
设置条件变量属性对象中的时钟属性。该属性指定 pthread_cond_timedwait() 用于计算超时的时钟源。
选择合适的时钟对于超时行为至关重要:
CLOCK_REALTIME:使用系统实时时钟,超时时间是绝对时间点。如果系统时间被向前调整,可能导致提前超时;向后调整则可能导致超时延迟。CLOCK_MONOTONIC:使用单调递增时钟,不受系统时间调整影响,适合需要精确超时控制的场景。
参数:
attr指向条件变量属性对象。不能为NULL。clock_id时钟 ID,必须为以下之一:CLOCK_REALTIME系统实时时钟(默认)。CLOCK_MONOTONIC单调递增时钟。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL,或clock_id不是CLOCK_REALTIME或CLOCK_MONOTONIC。
注意:
- 在 openvela 中,仅支持
CLOCK_REALTIME和CLOCK_MONOTONIC两种时钟,传入其他时钟 ID(如CLOCK_PROCESS_CPUTIME_ID)会返回EINVAL。 - 修改时钟属性不影响已创建的条件变量,仅影响后续使用该属性对象创建的条件变量。
- 如果使用
CLOCK_MONOTONIC,传递给pthread_cond_timedwait()的abstime应基于clock_gettime(CLOCK_MONOTONIC, ...)获取的时间计算。 - 也可以使用
pthread_cond_clockwait()在等待时直接指定时钟,而不依赖属性对象中的设置。
POSIX 兼容性:兼容 POSIX 同名接口。
读写锁
pthread_rwlock_init
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
初始化读写锁。读写锁允许多个线程同时持有读锁,但写锁是排他的。
参数:
rwlock指向要初始化的读写锁。不能为NULL。attr读写锁属性。如果为NULL,使用默认属性。
返回值:
成功时返回 0,失败时返回错误码:
EINVALrwlock为NULL。ENOMEM内存不足。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_rwlock_destroy
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
销毁读写锁。
参数:
rwlock指向要销毁的读写锁。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALrwlock为NULL。EBUSY读写锁当前被锁定。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_rwlock_rdlock
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
获取读锁。如果当前没有写锁被持有,立即获取成功;否则阻塞等待。多个线程可同时持有读锁。
参数:
rwlock指向读写锁。
返回值:
成功时返回 0,失败时返回错误码:
EINVALrwlock未正确初始化。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_rwlock_tryrdlock
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
尝试获取读锁(非阻塞)。
参数:
rwlock指向读写锁。
返回值:
成功时返回 0,失败时返回错误码:
EBUSY有写锁被持有,无法获取读锁。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_rwlock_timedrdlock
int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, const struct timespec *abstime);
带超时的获取读锁。如果读锁不能立即获取,阻塞等待直到锁可用或超时。超时基于 CLOCK_REALTIME。
参数:
rwlock指向读写锁。abstime绝对超时时间(基于CLOCK_REALTIME)。
返回值:
成功时返回 0,失败时返回错误码:
ETIMEDOUT在超时时间内未能获取读锁。EBUSY读锁不可用。EINVAL参数无效。
注意:
- 内部调用
pthread_rwlock_clockrdlock()并使用CLOCK_REALTIME作为时钟源。 - 如果需要使用
CLOCK_MONOTONIC,请使用pthread_rwlock_clockrdlock()。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_rwlock_clockrdlock
int pthread_rwlock_clockrdlock(pthread_rwlock_t *rwlock, clockid_t clockid,
const struct timespec *abstime);
使用指定时钟带超时获取读锁。
参数:
rwlock指向读写锁。clockid时钟 ID,如CLOCK_REALTIME或CLOCK_MONOTONIC。abstime基于指定时钟的绝对超时时间。
返回值:
成功时返回 0,失败时返回错误码:
ETIMEDOUT在超时时间内未能获取读锁。EINVAL参数无效。
POSIX 兼容性:兼容扩展接口。
pthread_rwlock_wrlock
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
获取写锁。写锁是排他的,必须等待所有读锁和写锁释放后才能获取。
参数:
rwlock指向读写锁。
返回值:
成功时返回 0,失败时返回错误码:
EINVALrwlock未正确初始化。EAGAIN写者数量已达上限。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_rwlock_trywrlock
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
尝试获取写锁(非阻塞)。
参数:
rwlock指向读写锁。
返回值:
成功时返回 0,失败时返回错误码:
EBUSY有读锁或写锁被持有,无法获取写锁。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_rwlock_timedwrlock
int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, const struct timespec *abstime);
带超时的获取写锁。如果写锁不能立即获取,阻塞等待直到锁可用或超时。超时基于 CLOCK_REALTIME。
参数:
rwlock指向读写锁。abstime绝对超时时间(基于CLOCK_REALTIME)。
返回值:
成功时返回 0,失败时返回错误码:
ETIMEDOUT在超时时间内未能获取写锁。EAGAIN写者数量已达上限。EINVAL参数无效。
注意:
- 内部调用
pthread_rwlock_clockwrlock()并使用CLOCK_REALTIME作为时钟源。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_rwlock_clockwrlock
int pthread_rwlock_clockwrlock(pthread_rwlock_t *rwlock, clockid_t clockid,
const struct timespec *abstime);
使用指定时钟带超时获取写锁。
参数:
rwlock指向读写锁。clockid时钟 ID,如CLOCK_REALTIME或CLOCK_MONOTONIC。abstime基于指定时钟的绝对超时时间。
返回值:
成功时返回 0,失败时返回错误码:
ETIMEDOUT在超时时间内未能获取写锁。EAGAIN写者数量已达上限。EINVAL参数无效。
POSIX 兼容性:兼容扩展接口。
pthread_rwlock_unlock
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
释放读写锁(读锁或写锁)。
参数:
rwlock指向读写锁。
返回值:
成功时返回 0,失败时返回错误码:
EINVALrwlock未正确初始化。EPERM当前线程未持有该锁。
POSIX 兼容性:兼容 POSIX 同名接口。
读写锁属性
pthread_rwlockattr_init
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
初始化读写锁属性对象为默认值。默认进程共享属性为 PTHREAD_PROCESS_PRIVATE。
参数:
attr指向要初始化的读写锁属性对象。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_rwlockattr_destroy
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);
销毁读写锁属性对象。
参数:
attr指向要销毁的读写锁属性对象。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_rwlockattr_setpshared
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared);
设置读写锁属性对象中的进程共享属性。
参数:
attr指向读写锁属性对象。不能为NULL。pshared进程共享属性值:PTHREAD_PROCESS_PRIVATE或PTHREAD_PROCESS_SHARED。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL,或pshared不是有效值。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_rwlockattr_getpshared
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, int *pshared);
获取读写锁属性对象中的进程共享属性。
参数:
attr指向读写锁属性对象。不能为NULL。pshared指向整型变量,用于存储进程共享属性值。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或pshared为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
屏障
pthread_barrier_init
int pthread_barrier_init(pthread_barrier_t *barrier,
const pthread_barrierattr_t *attr, unsigned int count);
初始化屏障。屏障用于同步多个线程,所有线程到达屏障后才能继续执行。
参数:
barrier指向要初始化的屏障。不能为NULL。attr屏障属性。如果为NULL,使用默认属性。count需要到达屏障的线程数。必须大于 0。
返回值:
成功时返回 0,失败时返回错误码:
EINVALbarrier为NULL,或count为 0。ENOMEM内存不足。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_barrier_destroy
int pthread_barrier_destroy(pthread_barrier_t *barrier);
销毁屏障。
参数:
barrier指向要销毁的屏障。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALbarrier为NULL。EBUSY有线程正在等待该屏障。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_barrier_wait
int pthread_barrier_wait(pthread_barrier_t *barrier);
在屏障处等待。当所有线程(数量由 pthread_barrier_init 的 count 参数指定)都调用此函数后,所有线程同时被释放继续执行。
参数:
barrier指向屏障。
返回值:
其中一个线程返回 PTHREAD_BARRIER_SERIAL_THREAD(该线程可用于执行清理工作),其他线程返回 0。
POSIX 兼容性:兼容 POSIX 同名接口。
屏障属性
pthread_barrierattr_init
int pthread_barrierattr_init(pthread_barrierattr_t *attr);
初始化屏障属性对象为默认值。默认进程共享属性为 PTHREAD_PROCESS_PRIVATE。
参数:
attr指向要初始化的屏障属性对象。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_barrierattr_destroy
int pthread_barrierattr_destroy(pthread_barrierattr_t *attr);
销毁屏障属性对象。
参数:
attr指向要销毁的屏障属性对象。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_barrierattr_setpshared
int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared);
设置屏障属性对象中的进程共享属性。
参数:
attr指向屏障属性对象。不能为NULL。pshared进程共享属性值:PTHREAD_PROCESS_PRIVATE或PTHREAD_PROCESS_SHARED。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr为NULL,或pshared不是有效值。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_barrierattr_getpshared
int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, int *pshared);
获取屏障属性对象中的进程共享属性。
参数:
attr指向屏障属性对象。不能为NULL。pshared指向整型变量,用于存储进程共享属性值。不能为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALattr或pshared为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。
自旋锁
pthread_spin_init
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
初始化自旋锁。自旋锁使用忙等待方式获取锁,适用于锁持有时间极短的场景。
参数:
lock指向要初始化的自旋锁。不能为NULL。pshared共享属性:PTHREAD_PROCESS_PRIVATE或PTHREAD_PROCESS_SHARED。
返回值:
成功时返回 0,失败时返回错误码:
EINVALlock为NULL。
注意:
- 自旋锁不应在持有时间较长的场景使用,会浪费 CPU 资源。
- 持有自旋锁时不应调用可能阻塞的函数。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_spin_destroy
int pthread_spin_destroy(pthread_spinlock_t *lock);
销毁自旋锁。
参数:
lock指向要销毁的自旋锁。
返回值:
成功时返回 0,失败时返回错误码:
EINVALlock未正确初始化。EBUSY自旋锁当前被锁定。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_spin_lock
int pthread_spin_lock(pthread_spinlock_t *lock);
获取自旋锁。如果锁已被持有,调用线程忙等待直到锁可用。
参数:
lock指向自旋锁。
返回值:
成功时返回 0,失败时返回错误码:
EINVALlock未正确初始化。EDEADLK当前线程已持有该锁(实现相关)。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_spin_trylock
int pthread_spin_trylock(pthread_spinlock_t *lock);
尝试获取自旋锁(非阻塞)。
参数:
lock指向自旋锁。
返回值:
成功时返回 0,失败时返回错误码:
EBUSY自旋锁已被锁定。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_spin_unlock
int pthread_spin_unlock(pthread_spinlock_t *lock);
释放自旋锁。
参数:
lock指向自旋锁。
返回值:
成功时返回 0,失败时返回错误码:
EINVALlock未正确初始化。EPERM当前线程未持有该锁。
POSIX 兼容性:兼容 POSIX 同名接口。
线程特定数据
pthread_key_create
int pthread_key_create(pthread_key_t *key, void (*destructor)(void *));
创建线程特定数据键。每个线程可以通过该键存储和获取自己的私有数据。
参数:
key指向pthread_key_t变量,用于存储创建的键。不能为NULL。destructor析构函数,线程退出时对非NULL的数据自动调用。可以为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EAGAIN已达系统键数量上限(PTHREAD_KEYS_MAX)。ENOMEM内存不足。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_key_delete
int pthread_key_delete(pthread_key_t key);
删除线程特定数据键。不会调用析构函数,也不会释放各线程关联的数据。
参数:
key要删除的键。
返回值:
成功时返回 0,失败时返回错误码:
EINVALkey无效。
注意:
- 删除键后,各线程应自行释放关联的数据,否则会导致内存泄漏。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_setspecific
int pthread_setspecific(pthread_key_t key, const void *value);
设置调用线程的线程特定数据。
参数:
key数据键,必须是通过pthread_key_create()创建的有效键。value要存储的值。可以为NULL。
返回值:
成功时返回 0,失败时返回错误码:
EINVALkey无效。ENOMEM内存不足。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_getspecific
void *pthread_getspecific(pthread_key_t key);
获取调用线程的线程特定数据。
参数:
key数据键。
返回值:
返回与键关联的值。如果键无效或未设置过值,返回 NULL。
注意:
- 此函数不返回错误码,无法区分"未设置"和"设置为 NULL"两种情况。
POSIX 兼容性:兼容 POSIX 同名接口。
线程清理
pthread_cleanup_push
void pthread_cleanup_push(void (*routine)(void *), void *arg);
注册线程清理函数。清理函数在线程被取消、调用 pthread_exit() 或调用 pthread_cleanup_pop(1) 时执行。
参数:
routine清理函数。不能为NULL。arg传递给清理函数的参数。
返回值:
无返回值。
注意:
- 必须与
pthread_cleanup_pop()配对使用,且在同一函数作用域内。 - 清理函数按注册顺序的逆序执行(后注册先执行)。
- 常用于确保互斥锁在线程取消时被释放。
POSIX 兼容性:兼容 POSIX 同名接口。
pthread_cleanup_pop
void pthread_cleanup_pop(int execute);
移除最近注册的清理函数,并可选择执行它。
参数:
execute如果非零,移除并执行清理函数;如果为零,仅移除不执行。
返回值:
无返回值。
注意:
- 必须与
pthread_cleanup_push()配对使用。 - 即使
execute为 0,清理函数也会从栈中移除。
POSIX 兼容性:兼容 POSIX 同名接口。
扩展接口
pthread_setname_np
int pthread_setname_np(pthread_t thread, const char *name);
设置线程名称。线程名称用于调试和日志,可通过 ps 命令或调试器查看。
参数:
thread线程 ID。name线程名称字符串。
返回值:
成功时返回 0,失败时返回错误码:
ESRCH找不到指定线程。EINVALname为NULL。
POSIX 兼容性:兼容 Linux 扩展接口。
pthread_getname_np
int pthread_getname_np(pthread_t thread, char *name, size_t len);
获取线程名称。
参数:
thread线程 ID。name用于存储名称的缓冲区。len缓冲区大小。
返回值:
成功时返回 0,失败时返回错误码:
ESRCH找不到指定线程。EINVALname为NULL。
POSIX 兼容性:兼容 Linux 扩展接口。
pthread_gettid_np
pid_t pthread_gettid_np(pthread_t thread);
获取线程的内核线程 ID(pid_t)。
参数:
thread线程 ID。
返回值:
返回内核线程 ID。
注意:
- 在 openvela 中,
pthread_t本身就是pid_t,因此此函数直接返回输入值。
POSIX 兼容性:兼容扩展接口。
pthread_getcpuclockid
int pthread_getcpuclockid(pthread_t thread, clockid_t *clockid);
获取线程的 CPU 时钟 ID。该时钟测量指定线程消耗的 CPU 时间。
参数:
thread线程 ID。clockid指向clockid_t变量,用于存储时钟 ID。
返回值:
成功时返回 0,失败时返回错误码:
ESRCH找不到指定线程。EINVALclockid为NULL。
POSIX 兼容性:兼容 POSIX 同名接口。