等待变量锁 (vutex)
SylixOS 引入了与 Linux futex 类似的用户快速锁 vutex(vitual user mutex)(SylixOS 习惯称为“等待变量锁”);vutex 包括两个操作:pend 和 post,pend 操作用于等待期望值得到满足,post 操作用于设置期望值,并唤醒等待的线程。
vutex 通过一个变量地址(整形变量)管理线程间的“锁”,该变量地址为用户空间地址,因此在同一个进程中,vutex 的 pend 与 post 操作使用同一个虚拟地址(内核通过该虚拟地址对应的物理地址进行期望值的管理);在两个不同的进程之间,则需要建立一个共享内存,实现使用同一个物理地址的目的。
vutex pend 操作
vutex pend 用于线程/进程等待一个期望的值,pend 操作可以设置线程/进程的等待方式(等待指定的时间、永久等待、不等待),如果等待方式设置为等待指定的时间(单位为 TICK),当时间超时后,期望的值仍然未满足,则 pend 函数返回错误并设置错误号(ERROR_THREAD_WAIT_TIMEOUT);如果等待方式为永久等待,则等待线程的期望值未满足之前将永远陷入等待,直到期望值满足或线程被删除;特殊地,如果等待方式设置为不等待,则 pend 函数仅尝试一次查询期望值,如果期望值不满足,pend 函数返回错误并设置错误号(ERROR_THREAD_WAIT_TIMEOUT)。
vutex pend 接口详细描述如下:
#include <SylixOS.h>
INT Lw_Vutex_Pend(INT *piVar, INT iDesired, ULONG ulTimeout)
INT Lw_Vutex_PendEx(INT *piVar, INT iCompare, INT iDesired, ULONG ulTimeout)
函数原型分析:
- 函数成功返回 0,失败返回-1 并设置错误号。
- 参数 piVar 是变量地址。
- 参数 iCompare 是比较方法,如下表所示。
- 参数 iDesired 是期待的值。
- 参数 ulTimeout 是等待的超时时间(单位为 TICK)。
参数 iCompare 指定了设置值与期望值得比较策略,这些比较策略拓宽了 pend 函数的使用场景,例如 GREATER_EQU 策略,允许在设置值大于期望值得时候满足条件,而不仅仅是必须等于期望值。
vutex 比较方法 | 说明 |
---|---|
LW_OPTION_VUTEX_EQU | 设置值与期望值相同 |
LW_OPTION_VUTEX_NOT_EQU | 设置值与期望值不相同 |
LW_OPTION_VUTEX_LESS | 设置值小于期望值 |
LW_OPTION_VUTEX_LESS_EQU | 设置值小于等于期望值 |
LW_OPTION_VUTEX_GREATER | 设置值大于期望值 |
LW_OPTION_VUTEX_GREATER_EQU | 设置值大于等于期望值 |
LW_OPTION_VUTEX_AND | 设置值完全包含期望值 |
LW_OPTION_VUTEX_NOT | 设置值不包含期望值 |
LW_OPTION_VUTEX_OR | 设置值部分包含期望值 |
vutex post 操作
vutex post 是 vutex pend 的反操作,post 将满足期望的值设置到变量地址(参数 piVar 指定的地址),post 设置完期望值后会唤醒被阻塞的线程,根据不同的使用场景,post 包括以下三种设置方式:
- 全部唤醒并阻塞的线程。
- 仅唤醒被阻塞的线程不设置期望值。
- 深度唤醒(设置期望值并唤醒单个线程)。
#include <SylixOS.h>
INT Lw_Vutex_Post(INT *piVar, INT iValue)
INT Lw_Vutex_PostEx(INT *piVar, INT iValue, INT iFlags)
函数原型分析:
- 函数成功返回 0,失败返回-1 并设置错误号。
- 参数 piVar 是变量地址。
- 参数 iValue 是要设置的值。
- 参数 iFlags 是 vutex 标志,如下表所示。
vutex 标志 | 说明 |
---|---|
LW_OPTION_VUTEX_FLAG_WAKEALL | 全部唤醒 |
LW_OPTION_VUTEX_FLAG_DONTSET | 不设置变量值 |
LW_OPTION_VUTEX_FLAG_DEEPWAKE | Post 不进行相同值检查优化 |
下面程序展示了 vutex 在两个线程间实现的同步作用。
#include <SylixOS.h>
#include <pthread.h>
static int *pvar = NULL;
static void *t_vpend (void *arg)
{
int ret;
printf("vutex start pend, expect value == 1\n");
ret = API_VutexPend(pvar, 1, LW_OPTION_WAIT_INFINITE);
printf("vutex pend return: %d\n", ret);
return (NULL);
}
static void *t_vpost (void *arg)
{
sleep(1);
printf("vutex post expect 1\n");
API_VutexPost(pvar, 1);
return (NULL);
}
int main (int argc, char **argv)
{
pthread_t tid0, tid1;
pthread_create(&tid0, NULL, t_vpend, NULL);
pthread_create(&tid1, NULL, t_vpost, NULL);
pthread_join(tid0, NULL);
pthread_join(tid1, NULL);
return (0);
}
在 SylixOS Shell 下运行程序:
# ./vutex_use
vutex start pend, expect value == 1
vutex post expect 1
vutex pend return: 0