事件集

更新时间:
2024-03-14
下载文档

事件集

我们一般都使用过 P2P 软件(如 BT、电骡等)下载过电影等,P2P 软件将需要下载的文件划分为许多个小片断,它从多个文件源下载这些不同的文件片断,当所有的文件片断下载完毕后,P2P 软件再将它们组装成一个文件:

P2P 软件需要记录这些文件片断的下载情况和实现在线播放的功能,SylixOS 提供的事件集这一线程间通信手段很好地解决了这些问题。

事件集被定义为 ULONG 型,每一位代表一个事件,对于上面的例子,每一位代表一个文件片断,这样就很好地解决了文件片断下载情况记录的问题。

而在线播放功能依赖于当前需要播放的文件片断,如果当前需要播放的文件片断未下载完,那么只能暂停播放了。下载和播放使用不同线程实现。下载线程不能简单地下载一个文件片断就唤醒播放线程进行播放,因为能下载到哪些文件片断是不确定的,当前下载到的文件片断不一定是播放线程当前需要的。事件集提供了发送和等待事件的 API,很好地解决了下载和播放线程同步的问题。

这里举了 P2P 软件的例子来说明事件集的用途,实际上事件集的功能不限于此。

一个 SylixOS 事件集必须要调用 Lw_Event_Create 函数创建之后才能使用,如果创建成功,Lw_Event_Create 函数会返回一个事件集的句柄。

线程如果需要等待事件,可以调用 Lw_Event_Wait 函数,中断服务程序不能调用 Lw_Event_Wait 函数等待事件,因为 Lw_Event_Wait 函数在事件无效时会阻塞当前线程。

中断服务程序可以使用 Lw_Event_TryWait 函数尝试等待事件,Lw_Event_TryWait 函数在事件无效时会立即返回,不会阻塞当前线程。

发送事件可以调用 Lw_Event_Send 函数。

当一个事件集使用完毕后(并确保以后也不再使用),应该调用 Lw_Event_Delete 函数删除它,SylixOS 会回收该事件集占用的内核资源。

事件集

事件集的创建和删除

#include <SylixOS.h>
LW_HANDLE   Lw_Event_Create(CPCHAR              pcName, 
                            ULONG               ulInitEvent, 
                            ULONG               ulOption,
                            LW_OBJECT_ID       *pulId);

函数 Lw_Event_Create 原型分析:

  • 此函数成功时返回事件集的句柄,失败时返回 LW_HANDLE_INVALID 并设置错误号。
  • 参数 pcName 是事件集的名字。
  • 参数 ulInitEvent 是事件集的初始值。
  • 参数 ulOption 是事件集的创建选项。
  • 输出参数 pulId 用于接收事件集的 ID。

事件可以用宏 LW_OPTION_EVENT_n(n 范围从 0 到 31)的组合,如果是所有事件,可以用宏 LW_OPTION_EVENT_ALL。

#include <SylixOS.h>
ULONG   Lw_Event_Delete(LW_HANDLE  *pulId);

函数 Lw_Event_Delete 原型分析:

  • 此函数成功时返回 ERROR_NONE,失败时返回错误号。
  • 参数 pulId 是接收事件集的句柄。

事件集的发送

#include <SylixOS.h>
ULONG    Lw_Event_Send(LW_HANDLE  ulId, 
                       ULONG      ulEvent,
                       ULONG      ulOption);

函数 Lw_Event_Send 原型分析:

  • 此函数成功时返回 ERROR_NONE,失败时返回错误号。
  • 参数 ulId 是事件集的句柄。
  • 参数 ulEvent 是需要发送的事件。
  • 参数 ulOption 是事件发送的选项,如下表所示。
宏名含义
LW_OPTION_EVENTSET_SET将指定事件设为 1
LW_OPTION_EVENTSET_CLR将指定事件设为 0

事件集的等待

#include <SylixOS.h>
ULONG    Lw_Event_Wait(LW_HANDLE  ulId, 
                       ULONG      ulEvent,
                       ULONG      ulOption,
                       ULONG      ulTimeout);                                           
ULONG    Lw_Event_WaitEx(LW_HANDLE  ulId, 
                         ULONG      ulEvent,
                         ULONG      ulOption,
                         ULONG      ulTimeout,
                         ULONG     *pulEvent); 
ULONG    Lw_Event_TryWait(LW_HANDLE  ulId, 
                          ULONG      ulEvent,
                          ULONG      ulOption);                                           
ULONG    Lw_Event_TryWaitEx(LW_HANDLE    ulId, 
                            ULONG        ulEvent,
                            ULONG        ulOption,
                            ULONG       *pulEvent);

以上函数原型分析:

  • 函数成功时返回 ERROR_NONE,失败时返回错误号。
  • 参数 ulId 是事件集的句柄。
  • 参数 ulEvent 是需要等待的事件。
  • 参数 ulOption 是等待事件的选项,如下表所示。
  • 参数 ulTimeout 是等待的超时时间,单位为时钟嘀嗒 Tick。
  • 输出参数 pulEvent 标识了接收到的事件。

Lw_Event_TryWait 和 Lw_Event_Wait 的区别在于,如果当前需要等待的事件无效,Lw_Event_TryWait 会立即退出,并返回 ERROR_THREAD_WAIT_TIMEOUT,而 Lw_Event_Wait 则会阻塞直至被唤醒。

宏名含义
LW_OPTION_EVENTSET_WAIT_CLR_ALL指定事件都为 0 时激活
LW_OPTION_EVENTSET_WAIT_CLR_ANY指定事件中任何一位为 0 时激活
LW_OPTION_EVENTSET_WAIT_SET_ALL指定事件都为 1 时激活
LW_OPTION_EVENTSET_WAIT_SET_ANY指定事件中任何一位为 1 时激活
LW_OPTION_EVENTSET_RETURN_ALL获得事件后返回所有有效的事件
LW_OPTION_EVENTSET_RESET获得事件后自动清除事件
LW_OPTION_EVENTSET_RESET_ALL获得事件后清除所有事件

获得事件集的状态

#include <SylixOS.h>
ULONG    Lw_Event_Status(LW_HANDLE   ulId, 
                         ULONG      *pulEvent,
                         ULONG      *pulOption); 

函数 Lw_Event_Status 原型分析:

  • 此函数成功时返回 ERROR_NONE,失败时返回错误号。
  • 参数 ulId 是事件集的句柄。
  • 输出参数 pulEvent 标识了当前置位的事件。
  • 输出参数 pulOption 是事件集的创建选项。

获得事件集的名字

#include <SylixOS.h>
ULONG    Lw_Event_GetName(LW_HANDLE  ulId,
                          PCHAR      pcName);

函数 Lw_Event_GetName 原型分析:

  • 此函数成功时返回 ERROR_NONE,失败时返回错误号。
  • 参数 ulId 是事件集的句柄。
  • 输出参数 pcName 是事件集的名字,pcName 应该指向一个大小为 LW_CFG_OBJECT_NAME_SIZE 的字符数组。

下面程序展示了 SylixOS 事件集的使用,程序创建两个线程和一个 SylixOS 事件集;线程 tTestB 不断地发送 0 到 31 号事件,线程 tTestA 等待事件并打印事件编号。

#include <SylixOS.h>

static LW_HANDLE    _G_hEventSet;

static PVOID tTestA (PVOID  pvArg)
{
    INT      iError;
    ULONG    ulEvent;
    INT      i;

    while (1) {
        iError = Lw_Event_WaitEx(_G_hEventSet,
                                 LW_OPTION_EVENT_ALL,
                                 LW_OPTION_EVENTSET_WAIT_SET_ANY |
                                 LW_OPTION_EVENTSET_RESET,
                                 LW_OPTION_WAIT_INFINITE,
                                 &ulEvent);
        if (iError != ERROR_NONE) {
            break;
        }
        for (i = 0; i < 32; i++) {
            if (ulEvent & (1 << i)) {
                printf("tTestA(): get event %d\n", i);
            }
        }
    }
    return  (LW_NULL);
}

static PVOID tTestB (PVOID  pvArg)
{
    INT     iError;
    INT     i;

    while (1) {
        for (i = 0; i < 32; i++) {
            iError = Lw_Event_Send(_G_hEventSet, (1 << i), LW_OPTION_EVENTSET_SET);
            if (iError != ERROR_NONE) {
                return  (LW_NULL);
            }
            Lw_Time_SSleep(1);
        }
    }
    return  (LW_NULL);
}
int main (int argc, char *argv[])
{
    LW_HANDLE         hThreadAId;
    LW_HANDLE         hThreadBId;

    _G_hEventSet = Lw_Event_Create("event_set", 0,
                                   LW_OPTION_WAIT_FIFO |
                                   LW_OPTION_OBJECT_LOCAL,
                                   LW_NULL);
    if (_G_hEventSet == LW_OBJECT_HANDLE_INVALID) {
        printf("event set create failed.\n");
        return  (-1);
    }
    hThreadAId = Lw_Thread_Create("t_testa", tTestA, LW_NULL, LW_NULL);
    if (hThreadAId == LW_OBJECT_HANDLE_INVALID) {
        printf("t_testa create failed.\n");
        return  (-1);
    }
    hThreadBId = Lw_Thread_Create("t_testb", tTestB, LW_NULL, LW_NULL);
    if (hThreadBId == LW_OBJECT_HANDLE_INVALID) {
        printf("t_testb create failed.\n");
        return  (-1);
    }
    Lw_Thread_Join(hThreadAId, LW_NULL);
    Lw_Thread_Join(hThreadBId, LW_NULL);
    Lw_Event_Delete(&_G_hEventSet);

    return  (0);
}

在 SylixOS Shell 下运行程序:

# ./SylixOS_Event_Set
tTestA(): get event 0
tTestA(): get event 1
tTestA(): get event 2
tTestA(): get event 3
tTestA(): get event 4
tTestA(): get event 5
tTestA(): get event 6
......
# ts
          NAME       TID    PID  PRI STAT LOCK SAFE    DELAY   PAGEFAILS FPU CPU
------------------ ------- ----- --- ---- ---- ---- ---------- --------- --- ---
SylixOS_Event_Set  4010066    32 200 JOIN    0               0         1 USE   0
t_testa            4010067    32 200 ENTS    0               0         0       0
t_testb            4010068    32 200 SLP     0             193         0       0
文档内容是否对您有所帮助?
有帮助
没帮助