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
    +关注

    关注

    87

    文章

    11245

    浏览量

    209069
  • WINDOWS
    +关注

    关注

    3

    文章

    3532

    浏览量

    88499
收藏 人收藏

    评论

    相关推荐

    Linux用户管理详解

    用户分为普通用户和超级用户,超级用户在Windows系统为Administrator在Linux系统
    的头像 发表于 11-01 09:48 128次阅读

    RTOS钩子函数的用途及用法

    在很多操作系统,都存在这样一类API函数接口:HOOK函数(也叫钩子函数)。
    的头像 发表于 10-23 16:25 200次阅读
    RTOS<b class='flag-5'>中</b>钩子<b class='flag-5'>函数</b>的用途及用法

    Windows操作系统的常用命令

    这些命令不仅能提高工作效率,还能帮助用户解决许多复杂的问题。本系列文章将详细介绍Windows操作系统的常用命令,帮助你成为Windows极客!
    的头像 发表于 08-07 15:40 567次阅读
    <b class='flag-5'>Windows</b>操作<b class='flag-5'>系统</b><b class='flag-5'>中</b>的常用命令

    研华工控机用什么系统WindowsLinux操作系统的较量

    工控机用什么系统WindowsLinux操作系统的较量。工控机(工业控制计算机)作为工业自动化和监控系统的核心组件,其稳定性、可靠性和性
    的头像 发表于 06-14 14:38 658次阅读
    研华工控机用什么<b class='flag-5'>系统</b>?<b class='flag-5'>Windows</b>与<b class='flag-5'>Linux</b>操作<b class='flag-5'>系统</b>的较量

    鸿蒙TypeScript学习第17天:【对象

    对象是包含一组键值对的实例。 值可以是标量、函数、数组、对象
    的头像 发表于 04-15 15:33 640次阅读
    鸿蒙TypeScript学习第17天:【<b class='flag-5'>对象</b>】

    3562-Linux系统启动卡制作及系统固化

    至 eMMC 的方 法。 使用瑞芯微创建升级磁盘工具 SDDiskTool_v1.74 可将 Linux 系统镜像通过读卡器固化 至 Micro SD 卡,将 Micro SD 卡制作成“SD
    的头像 发表于 03-05 15:58 299次阅读
    3562-<b class='flag-5'>Linux</b><b class='flag-5'>系统</b>启动卡制作及<b class='flag-5'>系统</b>固化

    Linux桌面操作系统市场份额首次突破4%,挑战Windows霸主地位

    Linux 市场份额的持续猛增,从 2020 年底的 1.53%上涨至现今的 4.03%,其背后原因可能归咎于 Windows 11 对硬件的严苛要求,例如许多计算机由于不满足 TPM 2.0 安全模块而无法升级至 Windows
    的头像 发表于 03-05 11:32 783次阅读

    广和通5G智能模组SC171支持Android、LinuxWindows系统

    世界移动通信大会2024期间,广和通宣布:5G智能模组SC171除支持Android操作系统外,还兼容LinuxWindows系统,帮助更多智能终端客户快速迭代产品,拓宽智能化应用覆
    的头像 发表于 02-28 17:39 513次阅读

    函数发生器的作用,概念要点是什么

    概念。 理解迭代器和可迭代对象: 在深入探讨函数生成器之前,我们需要先了解迭代器和可迭代对象的概念。在Python,迭代是一种访问集合元素的方式,无论集合的大小如何。迭代器是一个可以
    的头像 发表于 02-23 16:01 518次阅读

    linux服务器和windows服务器

    Linux服务器表现出更好的性能和稳定性,因此广泛应用于科学计算、大数据处理和网络服务器等领域。 另一方面,Windows服务器是由微软开发和维护的服务器操作系统,它提供了友好的用户
    发表于 02-22 15:46

    linuxwindows的区别 linux系统一般用来干嘛

    LinuxWindows是两种不同的操作系统,有着不同的设计理念和用途。本文将对LinuxWindows的区别进行详细分析,并介绍
    的头像 发表于 02-05 14:06 911次阅读

    linux用gdb调试遇到函数调用怎么办?

    linux用gdb调试遇到函数调用怎么办? 在Linux上使用GDB调试时,遇到函数调用是一个常见的情况。函数调用可能涉及到多个
    的头像 发表于 01-31 10:33 699次阅读

    pythonopen函数的用法详解

    pythonopen函数的用法详解 Python的open()函数用于打开文件。它接受文件名和模式作为参数,并返回一个文件对象。文件
    的头像 发表于 01-30 15:31 1997次阅读

    对象检测边界框损失函数–从IOU到ProbIOU介绍

    目标检测损失函数的选择在目标检测问题建模至关重要。通常,目标检测需要两个损失函数,一个用于对象分类,另一个用于边界框回归(BBR)。
    的头像 发表于 01-24 10:50 2635次阅读
    <b class='flag-5'>对象</b>检测边界框损失<b class='flag-5'>函数</b>–从IOU到ProbIOU介绍

    如何解决Linux系统的网络连接问题?

    如何解决Linux系统的网络连接问题? Linux系统的网络连接问题是常见的技术难题之一,通
    的头像 发表于 01-12 15:17 927次阅读