0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Linux和Windows系統(tǒng)中處理“事件”對(duì)象的函數(shù)

星星科技指導(dǎo)員 ? 來(lái)源:嵌入式計(jì)算設(shè)計(jì) ? 作者:Eduard Trunov ? 2022-11-30 15:21 ? 次閱讀

在 Windows 代碼庫(kù)中,有一個(gè)常量INFINITE,它由第二個(gè)參數(shù)傳遞。此常量指示線程無(wú)限期地等待事件。常量在WinBase.h中聲明,定義為0xFFFFFFFF(或 -1)。

此外,Windows代碼還包括WAIT_TIMEOUT。此條件在 Linux 中沒(méi)有表示。實(shí)際上,借助以下功能可以繞過(guò)此限制:

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幫助頁(yè)面,您可以看到EBUSY可能是一個(gè)錯(cuò)誤,并且 WaitForSingleObject無(wú)法通知我們。要了解線程的狀態(tài)并識(shí)別其退出代碼,必須調(diào)用該函數(shù):

BOOL GetExitCodeThread(HANDLE hThread, PDWORD pdwExitCode);

退出代碼作為pdwExitCode指向的變量返回。如果在調(diào)用函數(shù)時(shí)線程尚未終止,則STILL_ACTIVE標(biāo)識(shí)符將填充為變量。如果調(diào)用成功,則函數(shù)返回TRUE。

讓我們考慮一個(gè) Linux 的pthread_tryjoin_np函數(shù)用法和Windows 的 GetExitCodeThreadWaitForSingleObject函數(shù)的情況。

#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__

細(xì)心的讀者會(huì)注意到ADD_MS_TO_TIMESPEC是 Linux 操作系統(tǒng)中未表示的宏。 宏被添加到wait_time5000毫秒,但宏實(shí)現(xiàn)不在本文的討論范圍之內(nèi)。還應(yīng)該提到的是,在 Linux 中我們需要引入一個(gè)單獨(dú)的變量h_process_command_thread_initialized,因?yàn)閜thread_t是無(wú)符號(hào)的 long(一般來(lái)說(shuō)),我們無(wú)法驗(yàn)證它。

讓我們總結(jié)一下結(jié)果。Linux 和 Windows 操作系統(tǒng)提供了在應(yīng)用程序內(nèi)部創(chuàng)建線程的機(jī)會(huì)。在Windows操作系統(tǒng)中,類型是HANDLE和Linux-pthread_t。如果在 Linux 操作系統(tǒng)中創(chuàng)建可連接線程,即使我們確定線程已終止,也有必要編寫(xiě)pthread_join。這種做法將幫助我們避免系統(tǒng)資源泄漏。

討論的功能記錄在表 1 中。

Linux函數(shù) 窗口函數(shù)
pthread_create 開(kāi)始線程
pthread_join WaitForSingleObject(.., INFINITE)
pthread_timedjoin_np GetExitCodeThreadWaitForSingleObject
pthread_tryjoin_np 獲取退出代碼線程

表 1.Windows 和 Linux 操作系統(tǒng)中的線程同步函數(shù)。

事件

事件是內(nèi)核對(duì)象變體的實(shí)例。事件通知操作終止,通常在線程執(zhí)行初始化,然后向另一個(gè)線程發(fā)出可以繼續(xù)工作的信號(hào)時(shí)使用。初始化線程將 ?event? 對(duì)象轉(zhuǎn)換為無(wú)信號(hào)狀態(tài),然后繼續(xù)其操作。完成后,它將事件釋放到信號(hào)狀態(tài)。反過(guò)來(lái),一直在等待事件將其狀態(tài)更改為信號(hào)的另一個(gè)線程恢復(fù)并再次成為計(jì)劃線程。

讓我們來(lái)看看在Windows和Linux操作系統(tǒng)中處理“事件”對(duì)象的函數(shù)。

在Windows操作系統(tǒng)中,使用CreateEvent函數(shù)創(chuàng)建一個(gè)“事件”對(duì)象:

HANDLE CreateEvent(

PSECURITY_ATTRIBUTES psa,

BOOL fManualReset,

BOOL fInitialState,

PCSTR pszName

);

讓我們更清楚地關(guān)注fManualReset和fInitialState參數(shù)。BOOL類型的FManualReset參數(shù)通知系統(tǒng)需要?jiǎng)?chuàng)建手動(dòng)重置事件 (TRUE)或自動(dòng)重置事件 (FALSE)。fInitialState參數(shù)確定事件的初始狀態(tài):已發(fā)出信號(hào) (TRUE)或未發(fā)出信號(hào) (FALSE)。

創(chuàng)建事件后,可以管理狀態(tài)。要將事件轉(zhuǎn)換為信號(hào)狀態(tài),您需要調(diào)用:

Bool SetEvent(HANDLE hEvent);

若要將事件狀態(tài)更改為無(wú)信號(hào),需要調(diào)用:

Bool ResetEvent(HANDLE hEvent);

要等待事件信號(hào),您需要使用我們已經(jīng)熟悉的WaitForSingleObject函數(shù)。

在Linux操作系統(tǒng)中,“事件”對(duì)象表示整數(shù)描述符。一個(gè)整數(shù) ?event? 對(duì)象是使用eventfd函數(shù)創(chuàng)建的:

int eventfd(unsigned int initval, int flags);

initval參數(shù)是一個(gè)內(nèi)核服務(wù)計(jì)數(shù)器。flags參數(shù)是eventfd行為修改所必需的,可以是EFD_CLOEXEC、EFD_NONBLOCK或EFD_SEMAPHORE。如果成功終止,eventfd將返回一個(gè)新的文件描述符,該描述符可用于鏈接eventfd對(duì)象。

與SetEvent類似,我們可以使用eventfd_write調(diào)用:

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

從緩沖區(qū)調(diào)用寫(xiě)入時(shí),會(huì)將 8 字節(jié)整數(shù)值添加到計(jì)數(shù)器中。最大計(jì)數(shù)器值可以是 64 位無(wú)符號(hào)減 1。如果函數(shù)調(diào)用成功,則返回寫(xiě)入的字節(jié)數(shù)。

在我們討論ResetEvent類似物之前,讓我們看一下輪詢函數(shù)。

#include

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

輪詢功能允許應(yīng)用程序同時(shí)阻止多個(gè)描述符,并在其中任何一個(gè)準(zhǔn)備好讀取或?qū)懭霑r(shí)立即接收通知。民意調(diào)查工作(一般)可以描述如下:

當(dāng)任何描述符準(zhǔn)備好進(jìn)行輸入-輸出操作時(shí)發(fā)出通知。

如果沒(méi)有任何描述符準(zhǔn)備就緒,請(qǐng)進(jìn)入睡眠模式,直到一個(gè)或多個(gè)描述符準(zhǔn)備就緒。

如果有可用的描述符準(zhǔn)備用于輸入-輸出,請(qǐng)?zhí)幚硭鼈兌粫?huì)阻塞。

返回到步驟 1。

Linux 操作系統(tǒng)為多路復(fù)用輸入輸出提供了三個(gè)實(shí)體:用于選擇(選擇)、輪詢(輪詢)、擴(kuò)展輪詢(epoll)的接口。

那些有使用select經(jīng)驗(yàn)的人可能會(huì)欣賞投票的優(yōu)勢(shì),它使用更有效的方法,基于位掩碼使用三組描述符。輪詢調(diào)用適用于文件描述符指向的單個(gè)nfdspollfd結(jié)構(gòu)數(shù)組。

讓我們看一下pollfd結(jié)構(gòu)定義:

struct pollfd {

int fd; /* file descriptor */

short events; /* requested events */

short revents; /* returned events */

};

每個(gè)pollfd結(jié)構(gòu)中都指示了一個(gè)將被跟蹤的文件描述符。可以將多個(gè)文件描述符傳遞給輪詢函數(shù)(結(jié)構(gòu)的 pollfd數(shù)組)。fdarray數(shù)組中的元素?cái)?shù)由nfds參數(shù)確定。

為了將我們感興趣的事件傳達(dá)給內(nèi)核,有必要在數(shù)組中每個(gè)元素的事件字段中寫(xiě)入表 2 中的一個(gè)或多個(gè)值。從輪詢函數(shù)返回后,內(nèi)核指定每個(gè)描述符發(fā)生的事件。

名字 事件 活動(dòng) 描述
波林 + + 數(shù)據(jù)可供讀?。ǜ邇?yōu)先級(jí)除外)
波爾德規(guī)范 + + 常規(guī)數(shù)據(jù)(優(yōu)先級(jí) 0)可供讀取
波爾德班德 + + 具有非零優(yōu)先級(jí)的數(shù)據(jù)可供讀取
波普里普里 + + 高優(yōu)先級(jí)數(shù)據(jù)可供讀取
波羅特 + + 數(shù)據(jù)可供寫(xiě)入
波爾沃諾姆 + + 類似于 波勞特
民意調(diào)查帶 + + 具有非零優(yōu)先級(jí)的數(shù)據(jù)可用于寫(xiě)入
波勒爾 + 發(fā)生錯(cuò)誤
波爾赫普 + 連接丟失
波倫瓦爾 + 描述符和打開(kāi)的文件不匹配

表 2.事件和輪詢函數(shù)的revents標(biāo)志的可能值。

參數(shù)超時(shí)定義發(fā)生指定事件的等待時(shí)間。超時(shí)有三種可能的值。

timeout= -1:等待時(shí)間是無(wú)限的(在 WaitForSingleObject中為 INFINITE)。

timeout= 0:等待時(shí)間等于 0,表示需要檢查所有指定的描述符并將控制權(quán)交還給調(diào)用程序。

超時(shí)> 0:等待時(shí)間不超過(guò)超時(shí)毫秒。

在查看了輪詢函數(shù)之后,我們可以得出結(jié)論,在Windows操作系統(tǒng)中,“事件”對(duì)象與WaitForSingleObject類似。

讓我們轉(zhuǎn)到 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](實(shí)際上,這最初是由eventfd函數(shù)創(chuàng)建的,沒(méi)有錯(cuò)誤)。之后,我們初始化pollfd函數(shù)并運(yùn)行輪詢。需要執(zhí)行輪詢以檢查是否有可用的數(shù)據(jù)可供讀取。如果有此類數(shù)據(jù),我們將讀取它。

通過(guò)上述所有內(nèi)容的鏡頭,讓我們反映表3中的結(jié)果:

窗口函數(shù) Linux函數(shù)
創(chuàng)建事件 事件FD
設(shè)置事件 eventfd_write
重置事件 投票/eventfd_read
等待單個(gè)對(duì)象 民意調(diào)查

表 3.用于處理 Windows 中的事件及其在 Linux 中的類似事件的主要函數(shù)。

審核編輯:郭婷

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11123

    瀏覽量

    207920
  • WINDOWS
    +關(guān)注

    關(guān)注

    3

    文章

    3503

    瀏覽量

    87891
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Windows操作系統(tǒng)的常用命令

    這些命令不僅能提高工作效率,還能幫助用戶解決許多復(fù)雜的問(wèn)題。本系列文章將詳細(xì)介紹Windows操作系統(tǒng)的常用命令,幫助你成為Windows極客!
    的頭像 發(fā)表于 08-07 15:40 ?282次閱讀
    <b class='flag-5'>Windows</b>操作<b class='flag-5'>系統(tǒng)</b><b class='flag-5'>中</b>的常用命令

    研華工控機(jī)用什么系統(tǒng)WindowsLinux操作系統(tǒng)的較量

    工控機(jī)用什么系統(tǒng)?WindowsLinux操作系統(tǒng)的較量。工控機(jī)(工業(yè)控制計(jì)算機(jī))作為工業(yè)自動(dòng)化和監(jiān)控系統(tǒng)的核心組件,其穩(wěn)定性、可靠性和性
    的頭像 發(fā)表于 06-14 14:38 ?487次閱讀
    研華工控機(jī)用什么<b class='flag-5'>系統(tǒng)</b>?<b class='flag-5'>Windows</b>與<b class='flag-5'>Linux</b>操作<b class='flag-5'>系統(tǒng)</b>的較量

    3562-Linux系統(tǒng)啟動(dòng)卡制作及系統(tǒng)固化

    至 eMMC 的方 法。 使用瑞芯微創(chuàng)建升級(jí)磁盤(pán)工具 SDDiskTool_v1.74 可將 Linux 系統(tǒng)鏡像通過(guò)讀卡器固化 至 Micro SD 卡,將 Micro SD 卡制作成“SD
    的頭像 發(fā)表于 03-05 15:58 ?212次閱讀
    3562-<b class='flag-5'>Linux</b><b class='flag-5'>系統(tǒng)</b>啟動(dòng)卡制作及<b class='flag-5'>系統(tǒng)</b>固化

    linux服務(wù)器和windows服務(wù)器

    ,Linux服務(wù)器表現(xiàn)出更好的性能和穩(wěn)定性,因此廣泛應(yīng)用于科學(xué)計(jì)算、大數(shù)據(jù)處理和網(wǎng)絡(luò)服務(wù)器等領(lǐng)域。 另一方面,Windows服務(wù)器是由微軟開(kāi)發(fā)和維護(hù)的服務(wù)器操作系統(tǒng),它提供了友好的用戶
    發(fā)表于 02-22 15:46

    linuxwindows的區(qū)別 linux系統(tǒng)一般用來(lái)干嘛

    LinuxWindows是兩種不同的操作系統(tǒng),有著不同的設(shè)計(jì)理念和用途。本文將對(duì)LinuxWindows的區(qū)別進(jìn)行詳細(xì)分析,并介紹
    的頭像 發(fā)表于 02-05 14:06 ?681次閱讀

    pythonopen函數(shù)的用法詳解

    pythonopen函數(shù)的用法詳解 Python的open()函數(shù)用于打開(kāi)文件。它接受文件名和模式作為參數(shù),并返回一個(gè)文件對(duì)象。文件
    的頭像 發(fā)表于 01-30 15:31 ?1511次閱讀

    對(duì)象檢測(cè)邊界框損失函數(shù)–從IOU到ProbIOU介紹

    目標(biāo)檢測(cè)損失函數(shù)的選擇在目標(biāo)檢測(cè)問(wèn)題建模至關(guān)重要。通常,目標(biāo)檢測(cè)需要兩個(gè)損失函數(shù),一個(gè)用于對(duì)象分類,另一個(gè)用于邊界框回歸(BBR)。
    的頭像 發(fā)表于 01-24 10:50 ?2119次閱讀
    <b class='flag-5'>對(duì)象</b>檢測(cè)邊界框損失<b class='flag-5'>函數(shù)</b>–從IOU到ProbIOU介紹

    如何解決Linux系統(tǒng)的網(wǎng)絡(luò)連接問(wèn)題?

    如何解決Linux系統(tǒng)的網(wǎng)絡(luò)連接問(wèn)題? Linux系統(tǒng)的網(wǎng)絡(luò)連接問(wèn)題是常見(jiàn)的技術(shù)難題之一,通
    的頭像 發(fā)表于 01-12 15:17 ?625次閱讀

    php的mysqli_query的函數(shù)處理

    解釋它在處理數(shù)據(jù)庫(kù)查詢方面的重要性。 首先,讓我們來(lái)了解一下mysqli_query函數(shù)的基本語(yǔ)法: mixed mysqli_query ( mysqli $link , string $query
    的頭像 發(fā)表于 12-04 16:03 ?736次閱讀

    安裝Linuxwindows在哪啟動(dòng)

    操作系統(tǒng)引導(dǎo)加載程序,可以管理多個(gè)操作系統(tǒng)的啟動(dòng)。它允許用戶在系統(tǒng)啟動(dòng)時(shí)選擇要運(yùn)行的操作系統(tǒng)。本文將詳細(xì)介紹 Linux 安裝后
    的頭像 發(fā)表于 11-28 15:02 ?936次閱讀

    malloc在Linux上執(zhí)行的是哪個(gè)系統(tǒng)調(diào)用

    malloc底層為什么是內(nèi)存池 malloc大家都用過(guò),其是庫(kù)函數(shù)。我們都知道庫(kù)函數(shù)在不同的操作系統(tǒng)其實(shí)執(zhí)行的是系統(tǒng)調(diào)用,那么malloc
    的頭像 發(fā)表于 11-13 10:36 ?809次閱讀
    malloc在<b class='flag-5'>Linux</b>上執(zhí)行的是哪個(gè)<b class='flag-5'>系統(tǒng)</b>調(diào)用

    在單片機(jī)上實(shí)現(xiàn)動(dòng)態(tài)加載功能的函數(shù)庫(kù)介紹

    本項(xiàng)目是一個(gè)在單片機(jī)(如:STM32)上實(shí)現(xiàn)動(dòng)態(tài)加載功能的函數(shù)庫(kù),與Windows的dll,Linux的so類似,可以將代碼動(dòng)態(tài)地從其他
    的頭像 發(fā)表于 11-09 10:55 ?1224次閱讀

    linuxwindows的區(qū)別

    LinuxWindows是兩種不同的操作系統(tǒng),它們之間的區(qū)別包括: 源代碼開(kāi)放性:Linux是開(kāi)源的,意味著任何人都可以獲取并修改其源代碼,這為開(kāi)發(fā)者提供了很大的便利性。而
    的頭像 發(fā)表于 11-08 11:08 ?4918次閱讀

    Windows11上Linux安裝教程

    超簡(jiǎn)單,不安裝虛擬機(jī),Windows11運(yùn)行Linux
    發(fā)表于 10-24 15:11 ?1106次閱讀
    <b class='flag-5'>Windows</b>11上<b class='flag-5'>Linux</b>安裝教程

    linux系統(tǒng)中常見(jiàn)注冊(cè)函數(shù)的使用方法

    大家好,今天給大家分享一下,linux系統(tǒng)中常見(jiàn)的注冊(cè)函數(shù)register_chrdev_region()、register_chrdev()、 alloc_chrdev_region()的使用方法。
    發(fā)表于 10-19 09:28 ?419次閱讀
    <b class='flag-5'>linux</b><b class='flag-5'>系統(tǒng)</b>中常見(jiàn)注冊(cè)<b class='flag-5'>函數(shù)</b>的使用方法