0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux和Windows系统中处理“事件”对象的函数

星星科技指导员 来源:嵌入式计算设计 作者:Eduard Trunov 2022-11-30 15:21 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

在 Windows 代码库中,有一个常量INFINITE,它由第二个参数传递。此常量指示线程无限期地等待事件。常量在WinBase.h中声明,定义为0xFFFFFFFF(或 -1)。

此外,Windows代码还包括WAIT_TIMEOUT。此条件在 Linux 中没有表示。实际上,借助以下功能可以绕过此限制:

int pthread_tryjoin_np(pthread_t thread, void **retval);

int pthread_timedjoin_np(

pthread_t thread,

void **retval,

const struct timespec *abstime

);

如果您参考pthread_tryjoin_np帮助页面,您可以看到EBUSY可能是一个错误,并且 WaitForSingleObject无法通知我们。要了解线程的状态并识别其退出代码,必须调用该函数:

BOOL GetExitCodeThread(HANDLE hThread, PDWORD pdwExitCode);

退出代码作为pdwExitCode指向的变量返回。如果在调用函数时线程尚未终止,则STILL_ACTIVE标识符将填充为变量。如果调用成功,则函数返回TRUE。

让我们考虑一个 Linux 的pthread_tryjoin_np函数用法和Windows 的 GetExitCodeThreadWaitForSingleObject函数的情况。

#ifdef __PL_WINDOWS__

DWORD dwret;

BOOL bret;

DWORD h_process_command_thread_exit_code;

if (h_process_command_thread != NULL) {

bret = GetExitCodeThread(

h_process_command_thread,

&h_process_command_thread_exit_code

);

if (h_process_command_thread_exit_code == STILL_ACTIVE) {

dwret = WaitForSingleObject(

h_process_command_thread,

5000 // 5000ms

);

switch (dwret) {

case WAIT_OBJECT_0:

// everything from this point on is good break;

case WAIT_TIMEOUT:

case WAIT_FAILED:

default:

SetLastError(dwret);

break;

}

}

}

#endif //__PL_WINDOWS__

#ifdef __PL_LINUX__

int iret;

struct timespec wait_time = { 0 };

if (h_process_command_thread_initialized == 1) {

iret = pthread_tryjoin_np(

h_process_command_thread,

NULL

);

if ((iret != 0) && (iret != EBUSY)) {

//TODO: process the error

}

if (iret == EBUSY) {

clock_gettime(CLOCK_REALTIME, &wait_time);

ADD_MS_TO_TIMESPEC(wait_time, 5000);

iret = pthread_timedjoin_np(

h_process_command_thread,

NULL,

&wait_time

);

switch (iret) {

case 0:

// everything from this point on is good

break;

case ETIMEDOUT:

case EINVAL:

default:

break;

}

}

}

#endif //__PL_LINUX__

细心的读者会注意到ADD_MS_TO_TIMESPEC是 Linux 操作系统中未表示的宏。 宏被添加到wait_time5000毫秒,但宏实现不在本文的讨论范围之内。还应该提到的是,在 Linux 中我们需要引入一个单独的变量h_process_command_thread_initialized,因为pthread_t是无符号的 long(一般来说),我们无法验证它。

让我们总结一下结果。Linux 和 Windows 操作系统提供了在应用程序内部创建线程的机会。在Windows操作系统中,类型是HANDLE和Linux-pthread_t。如果在 Linux 操作系统中创建可连接线程,即使我们确定线程已终止,也有必要编写pthread_join。这种做法将帮助我们避免系统资源泄漏。

讨论的功能记录在表 1 中。

Linux函数 窗口函数
pthread_create 开始线程
pthread_join WaitForSingleObject(.., INFINITE)
pthread_timedjoin_np GetExitCodeThreadWaitForSingleObject
pthread_tryjoin_np 获取退出代码线程

表 1.Windows 和 Linux 操作系统中的线程同步函数。

事件

事件是内核对象变体的实例。事件通知操作终止,通常在线程执行初始化,然后向另一个线程发出可以继续工作的信号时使用。初始化线程将 «event» 对象转换为无信号状态,然后继续其操作。完成后,它将事件释放到信号状态。反过来,一直在等待事件将其状态更改为信号的另一个线程恢复并再次成为计划线程。

让我们来看看在Windows和Linux操作系统中处理“事件”对象的函数。

在Windows操作系统中,使用CreateEvent函数创建一个“事件”对象:

HANDLE CreateEvent(

PSECURITY_ATTRIBUTES psa,

BOOL fManualReset,

BOOL fInitialState,

PCSTR pszName

);

让我们更清楚地关注fManualReset和fInitialState参数。BOOL类型的FManualReset参数通知系统需要创建手动重置事件 (TRUE)或自动重置事件 (FALSE)。fInitialState参数确定事件的初始状态:已发出信号 (TRUE)或未发出信号 (FALSE)。

创建事件后,可以管理状态。要将事件转换为信号状态,您需要调用:

Bool SetEvent(HANDLE hEvent);

若要将事件状态更改为无信号,需要调用:

Bool ResetEvent(HANDLE hEvent);

要等待事件信号,您需要使用我们已经熟悉的WaitForSingleObject函数。

在Linux操作系统中,“事件”对象表示整数描述符。一个整数 «event» 对象是使用eventfd函数创建的:

int eventfd(unsigned int initval, int flags);

initval参数是一个内核服务计数器。flags参数是eventfd行为修改所必需的,可以是EFD_CLOEXEC、EFD_NONBLOCK或EFD_SEMAPHORE。如果成功终止,eventfd将返回一个新的文件描述符,该描述符可用于链接eventfd对象。

与SetEvent类似,我们可以使用eventfd_write调用:

ssize_t eventfd_write(int fd, const void *buf, size_t count);

从缓冲区调用写入时,会将 8 字节整数值添加到计数器中。最大计数器值可以是 64 位无符号减 1。如果函数调用成功,则返回写入的字节数。

在我们讨论ResetEvent类似物之前,让我们看一下轮询函数。

#include

int poll(struct pollfd fdarray[], nfds_t nfds, int timeout);

轮询功能允许应用程序同时阻止多个描述符,并在其中任何一个准备好读取或写入时立即接收通知。民意调查工作(一般)可以描述如下:

当任何描述符准备好进行输入-输出操作时发出通知。

如果没有任何描述符准备就绪,请进入睡眠模式,直到一个或多个描述符准备就绪。

如果有可用的描述符准备用于输入-输出,请处理它们而不会阻塞。

返回到步骤 1。

Linux 操作系统为多路复用输入输出提供了三个实体:用于选择(选择)、轮询(轮询)、扩展轮询(epoll)的接口

那些有使用select经验的人可能会欣赏投票的优势,它使用更有效的方法,基于位掩码使用三组描述符。轮询调用适用于文件描述符指向的单个nfdspollfd结构数组。

让我们看一下pollfd结构定义:

struct pollfd {

int fd; /* file descriptor */

short events; /* requested events */

short revents; /* returned events */

};

每个pollfd结构中都指示了一个将被跟踪的文件描述符。可以将多个文件描述符传递给轮询函数(结构的 pollfd数组)。fdarray数组中的元素数由nfds参数确定。

为了将我们感兴趣的事件传达给内核,有必要在数组中每个元素的事件字段中写入表 2 中的一个或多个值。从轮询函数返回后,内核指定每个描述符发生的事件。

名字 事件 活动 描述
波林 + + 数据可供读取(高优先级除外)
波尔德规范 + + 常规数据(优先级 0)可供读取
波尔德班德 + + 具有非零优先级的数据可供读取
波普里普里 + + 高优先级数据可供读取
波罗特 + + 数据可供写入
波尔沃诺姆 + + 类似于 波劳特
民意调查带 + + 具有非零优先级的数据可用于写入
波勒尔 + 发生错误
波尔赫普 + 连接丢失
波伦瓦尔 + 描述符和打开的文件不匹配

表 2.事件和轮询函数的revents标志的可能值。

参数超时定义发生指定事件的等待时间。超时有三种可能的值。

timeout= -1:等待时间是无限的(在 WaitForSingleObject中为 INFINITE)。

timeout= 0:等待时间等于 0,表示需要检查所有指定的描述符并将控制权交还给调用程序。

超时> 0:等待时间不超过超时毫秒。

在查看了轮询函数之后,我们可以得出结论,在Windows操作系统中,“事件”对象与WaitForSingleObject类似。

让我们转到 Linux 的ResetEvent类似物。

#ifdef __PL_LINUX__

struct pollfd wait_object;

uint64_t event_value;

int ret;

if (eventfd_descriptor > 0) { // Descriptor created by eventfd(0,0)

wait_object.fd = eventfd_descriptor;

wait_object.events = POLLIN;

wait_object.revents = 0;

ret = poll(&wait_object, 1, 0); // Do not wait

if (ret < 0) { // Error

} else {

if ((wait_object.revents & POLLIN) != 0) {

iret = eventfd_read(eventfd_descriptor, &event_value);

if (iret != 0) { // Error }

}

}

}

#endif //__PL_LINUX__

最初我们检查eventfd_descriptor是否大于零[2](实际上,这最初是由eventfd函数创建的,没有错误)。之后,我们初始化pollfd函数并运行轮询。需要执行轮询以检查是否有可用的数据可供读取。如果有此类数据,我们将读取它。

通过上述所有内容的镜头,让我们反映表3中的结果:

窗口函数 Linux函数
创建事件 事件FD
设置事件 eventfd_write
重置事件 投票/eventfd_read
等待单个对象 民意调查

表 3.用于处理 Windows 中的事件及其在 Linux 中的类似事件的主要函数。

审核编辑:郭婷

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    88

    文章

    11628

    浏览量

    217989
  • WINDOWS
    +关注

    关注

    4

    文章

    3697

    浏览量

    93236
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    WindowsLinux环境下分别使用Olimex和蜂鸟调试器下载程序

    备管理器显示可以识别设备,此后可以在Windows系统中下载程序了。 Olimex调试器和开发板的连接方式可以参考《手把手教你设计CPU--RISC-V处理器篇》第一版第
    发表于 10-31 08:26

    WindowsLinux 系统切换:聚徽工控一体机的系统迁移避坑经验

    开源、稳定、安全等特性,在实时控制、嵌入式系统等领域备受青睐。然而,在实际应用,企业可能因业务需求变化、系统升级等原因,需要在 Windows
    的头像 发表于 06-24 16:09 580次阅读

    龙芯处理器支持WINDOWS吗?

    龙芯处理器目前不支持原生运行Windows操作系统,主要原因如下: 架构差异 龙芯架构:龙芯早期基于MIPS架构,后续转向自主研发的LoongArch指令集(与x86/ARM不兼容
    发表于 06-05 14:24

    聚徽厂家解码——工控机操作系统选择:WindowsLinux、QNX 如何匹配工业场景

    在工业自动化进程不断推进的当下,工控机作为核心设备,其操作系统的恰当选择对工业生产的稳定性、高效性和安全性起着决定性作用。常见的 WindowsLinux 和 QNX 操作系统,各自
    的头像 发表于 05-29 16:28 1246次阅读

    详解Linux系统的服务管理

    Linux,无论何时当你安装任何带有服务和守护进程的包,系统默认会把这些服务的初始化及 systemd脚本添加进去,不过此时它们并没有被启用。
    的头像 发表于 05-23 15:10 626次阅读
    详解<b class='flag-5'>Linux</b><b class='flag-5'>系统</b><b class='flag-5'>中</b>的服务管理

    不借助Linux系统,在Windows下如何搭建ZMC900E交叉编译环境

    不需要依赖笨重的虚拟机,也不需要安装双系统。抛开繁琐的环境准备,在Windows上轻松搭建交叉编译环境。本文将介绍如何在Windows上搭建交叉编译环境,不借助Linux
    的头像 发表于 05-21 11:34 650次阅读
    不借助<b class='flag-5'>Linux</b><b class='flag-5'>系统</b>,在<b class='flag-5'>Windows</b>下如何搭建ZMC900E交叉编译环境

    Linux系统管理的核心概念

    在前一篇文章,我们深入探讨了Linux的文件操作命令,如cp、mv、rm,以及文本处理命令grep、wc和管道符。本文将继续深入Linux
    的头像 发表于 05-15 17:05 494次阅读

    如何将FX3与WSL(LinuxWindows系统)一起使用?

    如何将 FX3 与 WSL(LinuxWindows系统)一起使用? 我在 /dev/ 找不到任何设备 我有许多项目在 Windows
    发表于 05-06 07:11

    飞凌嵌入式ElfBoard ELF 1板卡-Linux系统中断之Linux中断介绍

    一、Linux系统中使用中断的一般步骤(一)中断请求(IRQ Request):驱动程序使用request_irq()函数向内核请求分配中断资源,并注册中断处理程序。该
    发表于 03-27 10:28

    详解RTOS的Hook函数

    Hook函数是RTOS的一个关键特性,通过该函数,用户可以增强对任务管理的控制,定义系统行为。
    的头像 发表于 03-24 16:14 840次阅读

    鸿道Intewell操作系统为半导体行业打造高可靠实时控制系统

    。在半导体制造Windows/Linux系统可用于运行人机界面(HMI)、数据处理和可视化等非实时任务,而鸿道Intewell实时
    的头像 发表于 02-08 16:13 786次阅读
    鸿道Intewell操作<b class='flag-5'>系统</b>为半导体行业打造高可靠实时控制<b class='flag-5'>系统</b>

    如何实现Windows应用在Linux系统上的无缝运行

    统信 Windows 应用兼容引擎 V3.0 的推出,让用户可以在 deepin 系统上直接双击.exe文件运行 Windows 应用程序。 近期,我们收到了大家诸多的反馈信息。基于这些反馈,我们
    的头像 发表于 12-30 09:51 2537次阅读
    如何实现<b class='flag-5'>Windows</b>应用在<b class='flag-5'>Linux</b><b class='flag-5'>系统</b>上的无缝运行

    Ubuntu系统的优缺点分析 Ubuntu系统Windows的比较

    Ubuntu是一个基于Linux的开源操作系统,它以其稳定性、安全性和社区支持而闻名。以下是对Ubuntu系统优缺点的分析,以及与Windows系统
    的头像 发表于 12-12 14:31 5406次阅读

    如何在Windows安装Ubuntu系统

    Windows安装Ubuntu系统通常有两种方法:使用虚拟机软件安装Ubuntu作为虚拟机,或者使用双启动安装Ubuntu与Windows共存。以下是两种方法的步骤: 方法一:使用
    的头像 发表于 12-12 14:29 3168次阅读

    Hyper-V创建虚拟机配置IP等网络配置原理(LinuxWindows为例)

    大家知道Windows系统里面内置了Hyper-V管理器,用来创建和管理本地虚拟机环境。今天我创建了两台虚拟机,一台是CentOS7.9(Linux),另一台是Windows 11,然
    的头像 发表于 12-09 10:24 5587次阅读
    Hyper-V创建虚拟机配置IP等网络配置原理(<b class='flag-5'>Linux</b>、<b class='flag-5'>Windows</b>为例)