1.ThreadX 提供 32 位计数信号灯,其值范围在 0 到 4,294,967,295 之间。每个计数信号灯都是一个公用资源。
2.两个操作:
tx_semaphore_get 和 tx_semaphore_put 。 执行获取操作会将信号灯数量减一。 如果信号灯为 0,获取操作不会成功; 获取操作的逆操作是放置操作。 该操作会将信号灯数量加一。
3.互相排斥
互相排斥用于控制线程对某些应用程序区域(也称为关键部分或应用程序资源)的访问 。
将信号灯用于互相排斥时,信号灯的“当前计数”表示允许访问的线程总数。 在大多数情况下,用于互相排斥的计数信号灯的初始值为1,这意味着每次只有一个线程可以访问关联的资源。 只有 0 或 1 值的计数信号灯称为二进制信号灯。
4.事件通知
采用生成者-使用者的方式,将计数信号灯用作事件通知。 使用者尝试获取计数信号灯,而生成者则在有可用的信息时增加信号灯。
此类信号灯的初始值通常为 0,此值不会在生成者为使用者准备好信息之前增加。 tx_semaphore_ceiling_put可确保信号灯计数值永远不会超过调用中提供的值。
5.创建计数信号灯
计数信号灯由线程在初始化期间或运行时创建。 信号灯的初始计数在创建过程中指定。 应用程序中计数信号灯的数量没有限制。
6.线程挂起
尝试对当前计数为 0 的信号灯执行获取操作时,应用程序线程可能会挂起。
执行放置操作后,才会执行挂起线程的获取操作并恢复该线程。 如果同一计数信号灯上挂起多个线程,这些线程将按照FIFO恢复。
tx_semaphore_prioritize可以恢复优先级。信号灯设置优先级服务将优先级最高的线程放于挂起列表的前面,同时让所有其他挂起的线程采用相同的 FIFO顺序。
7.信号灯放置通知
tx_semaphore_put_notify将应用程序通知函数注册到指定的信号灯。只要放置了信号灯,就会通知函数。
8.信号灯事件链接(semaphore event chaining)
当单个线程必须处理多个同步事件时,很有用。
如:应用程序可以为每个对象注册一个通知例程,而不是为队列消息、事件标志和信号灯而挂起单独的线程。在调用后,应用程序通知例程会恢复单个线程,该线程可以询问每个对象以查找并处理新事件。
9.运行时信号灯性能信息
通过 tx_semaphore_performance_info_get 和 tx_semaphore_performance_system_info_get获得
(1) 整个系统的总数
信号灯放置数、信号灯获取数、信号灯获取挂起数、信号灯获取超时数
(2) 每个信号灯的总数
信号灯放置数、信号灯获取数、信号灯获取挂起数、信号灯获取超时数
10.信号灯控制块 TX_SEMAPHORE
11.死锁/抱死
(1) 概念
抱死/死锁是指两个或多个线程在尝试获取归对方所有的信号灯时无限期挂起的情况。
(2) 示例
假设第一个线程拥有第一个信号灯,第二个线程拥有第二个信号灯。 如果第一个线程尝试获取第二个信号灯,同时第二个线程尝试获取第一个信号灯,这两个线程就会进入死锁状态。 此外,如果这些线程永远保持挂起状态,与之关联的资源也会永久锁定。
(3) 解决方案
可以通过对线程获取信号灯的方式设置一些限制来防止抱死。 线程每次只能拥有一个信号灯。或者,如果线程按照相同的顺序收集多个信号灯,则可以拥有这些信号灯。
在前面的示例中,如果第一个和第二个线程按顺序获取第一个和第二个信号灯,则可防止抱死。