Sofia的同步与多线程

        本文介绍Sofia的同步与多线程接口。

        Sofia工具库提供了简单的,不依赖操作系统的同步接口。同步接口包含用于管理 事件、消息、时间和多线程的原语。

克隆对象

        通过克隆,可以把进程分为多个任务。

        几个任务可以运行在一个线程的上下文中,也可以每个任务运行自己的线程。但是,只有一个任务中的代码,只能由一个线程执行。线程与任务间的关系是1对N的。软件中的多任务,既可以由多线程环境中的多个线程执行;也可以由单线程环境中的单一线程执行。

        克隆有利于使用独立线程处理多任务又不造成过多阻塞。当多线程不可用或不需要时,也可以在单线程模式下运行克隆。在单线程模式下进行debug调试是特别有帮助的。

        通过 su_clone_start()函数任务创建克隆。每次克隆都有它的根对象(su_root_t),它持有一个上下文指针(su_root_magic_t *)。上下文对象可以不同于父任务的对象。

        当任务克隆开始时,调用克隆初始化函数。初始化函数执行所有需要初始化的东西,注册IO事件和定时器,然后返回。如果初始化成功,克隆任务返回运行事件循环并调用事件回调函数,直到其父任务调用 su_clone_wait()才停止,它还会调用清理函数。克隆任务在清理函数返回时被销毁。

        公共API包含以下函数:

注意:

        每个线程只有一个事件循环,它可以共享给多个克隆任务。因此,克隆任务不能显式运行或设置事件循环,它们仅限于事件回调。克隆任务不能调用su_root_break()su_root_run() 或 su_root_step()这些函数。

任务与根(root)对象

        在Sofia的事件驱动编程模型中,任务是基本的执行单元。

        根据模型,程序可以要求事件循环在某个特定事件触发时调用回调函数。这类事件包括:I/O活动、定时器,或其它任务的消息。事件循环通过su_root_run() 或 su_root_step()函数执行。

        Root 对象可以访问任务控件。root对象代理在任务中执行的任务代码。通过root,任务代码可以访问它的context对象和线程同步功能,比如说等待对象、定时器,还有消息。

        在任务之间发消息时,使用任务引用 su_task_r 描述任务的地址。引用计数器可以保证任务引用的有效性。

        公用API包含以下函数:

        通过su_clone_start() 函数可以创建新的任务。

注册等待对象

        当应用程序希望捕获I/O事件时,它可以使用 su_root_register() 函数创建并注册一个等待对象,这时需要一个回调函数指针和一个指向su_root_t 对象的context指针。当等待对象收到相应事件时,会调用注册的回调函数。

        注册成功时, su_root_register()返回一个非负小整数描述注册本身。可以通过su_root_eventmask()函数操作注册,例如:通过socket发送数据时,应用程序可以向掩码是添加SU_WAIT_OUT事件。

        可以使用 su_root_deregister() 函数删除之前的注册信息。

定时器对象

        用定显示器安排在特定时间或间隔多少时间后执行给定任务。

The default interval is specified when the timer is created. We call timer activation "setting the timer", and deactivation "resetting the timer" (as in SDL). When the given time has arrived or the default interval has elapsed, the timer expires and it is ready for execution.

        创建定时器时指定默认时间间隔。 我们把定时器激活称为“设置计时器”,把取消激活称为“重置定时器”(如SDL)。 当给定时间到达或默认间隔过去时,定时器到期触发,执行给定任务。

        以下是用于创建、销毁、激活,管理定时器的相关函数:

注意:

        定时器使用poll()唤醒等待线程。在Linux环境下,定时器的精度是由HZ内核参数决定的,它取决于内核编译时的参数设定。内核2.4版本中,默认精度是10毫秒,定时器的最小持续时间间隔是20毫秒。当然,使用RTC可以获得更高的精度,但使用64Hz以上的RTC是一种特权操作。

        在Windows环境中,定时器的精度取决于实时时钟定时器。默认条件下,它使用18.78 Hz的精度。使用Windows多媒体库时,时钟精度可以调整为1000 Hz。

使用定时器

        调用su_timer_create()函数创建一个定时器:

   timer = su_timer_create(su_root_task(root), 200);

        时间间隔的单件是毫秒。

        通常,应该定期调用定时器的唤醒函数。这时,使用su_timer_set_for_ever()函数激活定时器。当定时器被激活时,它被赋予了唤醒函数和指向上下文数据的指针:

   su_timer_set_for_ever(timer, timer_wakeup, args);

        当指定的时间间隔过去时,root事件循环调用唤醒函数:

   timer_wakeup(root, timer, args);

        如果调用回调函数的次数很重要,请使用su_timer_run()。run timer会尝试补偿错过的时间,并在需要时多次调用回调函数。(因为可以调整实时时钟,或者把程序挂起,比如说在调试时,可以连续调用数千次回调函数。)请注意,虽然定时器尝试补偿回调之前和期间发生的延迟,但它不能用作计时信息的确切来源

        调用su_timer_reset() ,定时器停止运行。

        或者,可以将定时器设置为一次事件调用。设置定时器时,它绑定唤醒函数和上下文相关数据。也可以使用using su_timer_set_at()指定实际持续时间。

 su_timer_set(timer, timer_wakeup, args);

        定时器超时触发时,root事件循环会调用唤醒函数:

   timer_wakeup(root, timer, args);

        如果不再需要定时器事件,可以重置定时器:

   su_timer_reset(timer);

        如果希望定期调用定时器,可以通过su_timer_run()设置ro为持续运行。当持续运行的定时器激活时,不能调用 su_timer_set() 或 su_timer_set_at()进行设置。

        如果不再需要定时器,应当销毁定时器对象本身:

   su_timer_destroy(timer);

等待对象

      可以使用等待对象信进程发送I/O事件信号。

以下是事件类型:

  • SU_WAIT_IN - 输入数据在socket上可用
  • SU_WAIT_OUT - 数据可以通过socket发送
  • SU_WAIT_ERR - socket错误
  • SU_WAIT_HUP - socket连接关闭
  • SU_WAIT_ACCEPT - 监听中的socket接受一个新的连接尝试

        可以通过管道符|,二进制数或操作符将几个事件组合。

        可以通过以下几个函数管理等待对象:

注意:

在Unix平台下,,等待对象是个poll结构体。它包含一个文件描述符,一个描述预期事件的掩码,还有一个容纳su_wait()调用之后发生事件的掩码,比如说poll()。

Windows平台下,等待对象是一个HANDLE (Windows 内核实体的描述符)。


变量文档

int su_root_size_hint

包含su_root_t所支持的socket的数量的提示。

提示在su_root是已注册的fd的数量。

猜你喜欢

转载自blog.csdn.net/yetyongjin/article/details/105712707