(四)SylixOS同步互斥之互斥锁

gewenbin
gewenbin
gewenbin
188
文章
15
评论
2021年7月14日21:21:19 评论 776

从本篇开始往后的文章主要介绍下SylixOS常用的编程接口,比如同步互斥接口、动态内存相关类接口、Cache操作接口等等,主要聚焦于驱动开发中经常使用到的内核接口。

1. 基本作用

互斥锁在SylixOS中也被叫做互斥信号量,它的主要作用就是保护一段“共享资源”避免被同时访问,从而达到互斥的效果。比如在一般的网卡或者SD卡驱动中,硬件模块的数据收发都是通过描述符来进行设置的,当一个线程或者进程在更新或者准备这些描述符数据时,这些描述符是不可以再被别的线程来访问的,不然的话你前面一个线程设置好的描述符还没开始用立马又被别的线程给更改了,这就造成描述符的混乱从而导致收发数据异常。在这个案例中,描述符数据就是“共享资源”,访问这些数据可以使用互斥锁进行保护。

当一个线程成功获取到互斥锁后,就可以正常去访问“共享资源”,如果这时候另外的线程也来获取互斥锁,一般会被阻塞住,直到获取到锁的线程访问完“共享资源”,然后释放锁的时候会唤醒这些阻塞住的线程,从中选择一个优先级最高的调度运行。

互斥锁的详细使用方法在《SylixOS应用开发手册》的7.3.3章节有介绍,这里只介绍基本用法和使用过程中的一些注意事项或者比较重要的东西。

2. 互斥锁相关接口

2.1 创建互斥锁

互斥锁在使用之前需要进行创建,创建成功后会获得一个互斥锁句柄,后续的操作都是基于这个句柄来进行的。互斥锁创建使用接口API_SemaphoreMCreate 来实现,这个接口可以在应用层使用也可以在内核和驱动中使用,其函数原型如下:

LW_API LW_OBJECT_HANDLE API_SemaphoreMCreate(CPCHAR             pcName,
                                             UINT8              ucCeilingPriority,
                                             ULONG              ulOption,
                                             LW_OBJECT_ID      *pulId); /*  建立互斥信号量              */
  • pcName:互斥锁的名字,给每个互斥锁取不同的名字在一个使用超多互斥锁的工程进行调试时十分有用(经验之谈)。名字可以为空。
  • ucCeilingPriority:当使用优先级天花板算法时, 此参数表示天花板优先级。使用互斥锁时可能会发生优先级翻转问题,解决方法就是使用优先级继承或者优先级天花板算法,具体的原理请自行查阅相关资料。
  • ulOption:互斥锁的一些属性,比如优先级翻转解决算法、是否使用递归加锁等等。
  • pulId:当互斥锁成功创建后,可以通过此出参返回互斥锁句柄,也可以直接通过创建接口返回值来返回,取决于具体的使用环境,一般设置为空。

此接口成功创建返回互斥锁句柄,失败返回LW_OBJECT_HANDLE_INVALID 。另外有个比较重要的地方需要注意,就是ulOption中有一个LW_OPTION_OBJECT_GLOBAL 标志,当在驱动中使用此接口创建互斥锁时,一定要加上这个属性标志,在应用层使用此接口时则使用的是LW_OPTION_OBJECT_LOCAL 这个标志,一定要铭记!!!

GLOBAL那个标志控制着当进程结束时是否自动销毁此互斥锁资源。在SylixOS下,互斥锁、二进制信号量等其他内核对象都属于资源,当互斥锁没有设置GLOBAL标志时,进程退出时如果没有回收这些资源,系统会帮忙自动回收这些资源。这种机制对于应用层来说没有啥问题,因为即使你在应用中不手动销毁互斥锁,系统会帮你销毁以回收资源,但是在驱动中就有问题了。比如在某些驱动中,当初次被某个进程使用时会动态创建一些互斥锁等资源以用于驱动功能管理,当再次被别的进程使用时是不会再次去创建这些资源,这些资源只有在驱动卸载时才会被销毁回收。也就是说这些资源虽然是在第一个进程使用的过程中创建的,却不能在第一个进程结束时被系统来回收,这就是通过在创建时加上GLOBAL标志来实现的。所以在驱动中创建这些资源时都需要加上这个GLOBAL标志。

2.2 获取互斥锁

创建好互斥锁之后,在访问“共享资源”之前需要申请互斥锁或者叫获取互斥锁,在SylixOS下这是通过API_SemaphoreMPend 接口实现的,如下所示。

LW_API ULONG            API_SemaphoreMPend(LW_OBJECT_HANDLE  ulId, 
                                           ULONG             ulTimeout);/*  等待互斥信号量              */
  • ulId:这是之前创建的互斥锁句柄。
  • ulTimeout:等待互斥锁的时间。单位为tick,如果想一直等待,则设置为LW_OPTION_WAIT_INFINITE 即可。

此接口成功返回0,失败返回错误码,比如等待超时会返回ERROR_THREAD_WAIT_TIMEOUT

2.3 释放互斥锁

当访问完“共享资源”后,需要释放互斥锁以让别的线程或者进程来访问“共享资源”,在SylixOS下这是通过API_SemaphoreMPost 接口实现的,如下所示。

LW_API ULONG            API_SemaphoreMPost(LW_OBJECT_HANDLE  ulId);     /*  释放互斥信号量              */
  • ulId:成功创建的互斥锁句柄。

此接口会检查是否有别的线程在等待获取此互斥锁,如果有则将所有等待线程中优先级最高的线程加入调度就绪表。成功则返回0,失败返回错误码。

2.5 销毁互斥锁

由于互斥锁是占用系统资源的,如果确认使用完毕的话需要进行销毁以回收系统资源,在SylixOS下这是通过API_SemaphoreMDelete 接口实现的,如下所示。

LW_API ULONG            API_SemaphoreMDelete(LW_OBJECT_HANDLE  *pulId); /*  删除互斥信号量              */
  • pulId:要销毁的互斥锁句柄变量的地址。

成功返回0,失败返回错误码。

3. 接口使用示例

这里用伪代码来说明上述接口的基本使用方法,详细的使用请参考应用开发手册。

LW_OBJECT_HANDLE mutex;

1. 创建互斥锁
mutex = Lw_SemaphoreM_Create("lock",
                             LW_PRIO_HIGH,
                             LW_OPTION_WAIT_FIFO | LW_OPTION_OBJECT_GLOBAL| LW_OPTION_INHERIT_PRIORITY,
                             LW_NULL);

2. 获取互斥锁,如果获取不到则一直等待
API_SemaphoreMPend(mutex, LW_OPTION_WAIT_INFINITE);

3. 访问共享资源

4. 释放互斥锁
API_SemaphoreMPost(mutex);

5. 删除互斥锁
API_SemaphoreMDelete(&mutex);

为了简洁,上述代码没有进行函数调用返回值检查,在实际的使用中一定要记得检查函数调用的返回值。

关于互斥锁还有其他一些接口,具体可以参见内核源码SylixOS/kernel/include/k_api.h。

4.注意事项

  • 互斥锁只能使用在线程上下文环境,禁止在中断上下文中使用,否则会返回错误。
  • 互斥锁的获取和释放两个操作要成对的在同一个线程中使用,不要在不同的线程中使用。
gewenbin
  • 本文由 发表于 2021年7月14日21:21:19
  • 转载请务必保留本文链接:http://www.databusworld.cn/10389.html
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: