自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

在 Linux 中創(chuàng)建定時(shí)器

系統(tǒng) Linux
這是一個(gè)演示如何創(chuàng)建 POSIX 兼容的間隔定時(shí)器的教程。

對(duì)開發(fā)人員來說,定時(shí)某些事件是一項(xiàng)常見任務(wù)。定時(shí)器的常見場(chǎng)景是看門狗、任務(wù)的循環(huán)執(zhí)行,或在特定時(shí)間安排事件。在這篇文章中,我將演示如何使用 ??timer_create(...)?? 創(chuàng)建一個(gè) POSIX 兼容的間隔定時(shí)器。

你可以從 ??GitHub?? 下載下面樣例的源代碼。

準(zhǔn)備 Qt Creator

我使用 ??Qt Creator??? 作為該樣例的 IDE。為了在 Qt Creator 運(yùn)行和調(diào)試樣例代碼,請(qǐng)克隆 ??GitHub?? 上的倉庫,打開 Qt Creator,在 “文件File -> 打開文件或項(xiàng)目……Open File or Project...” 并選擇 “CMakeLists.txt”:

在 Qt Creator 中打開項(xiàng)目

在 Qt Creator 中打開項(xiàng)目

選擇工具鏈之后,點(diǎn)擊 “配置項(xiàng)目Configure Project”。這個(gè)項(xiàng)目包括三個(gè)獨(dú)立的樣例(我們?cè)谶@篇文章中將只會(huì)用到其中的兩個(gè))。使用綠色標(biāo)記出來的菜單,可以在每個(gè)樣例的配置之間切換,并為每個(gè)樣例激活在終端運(yùn)行 “在終端中運(yùn)行Run in terminal”(用黃色標(biāo)記)。當(dāng)前用于構(gòu)建和調(diào)試的活動(dòng)示例可以通過左下角的“調(diào)試Debug” 按鈕進(jìn)行選擇(參見下面的橙色標(biāo)記)。

項(xiàng)目配置

項(xiàng)目配置

線程定時(shí)器

讓我們看看 ??simple_threading_timer.c??? 樣例。這是最簡(jiǎn)單的一個(gè)。它展示了一個(gè)調(diào)用了超時(shí)函數(shù) ??expired??? 的間隔定時(shí)器是如何被創(chuàng)建的。在每次過期時(shí),都會(huì)創(chuàng)建一個(gè)新的線程,在其中調(diào)用函數(shù) ??expired??:

#include <stdio.h>#include <stdlib.h>#include <time.h>#include <signal.h>#include <unistd.h>#include <string.h>#include <errno.h>void expired(union sigval timer_data);pid_t gettid(void);struct t_eventData{    int myData;};int main(){    int res = 0;    timer_t timerId = 0;    struct t_eventData eventData = { .myData = 0 };    /*  sigevent 指定了過期時(shí)要執(zhí)行的操作  */    struct sigevent sev = { 0 };    /* 指定啟動(dòng)延時(shí)時(shí)間和間隔時(shí)間     * it_value和it_interval 不能為零 */    struct itimerspec its = {   .it_value.tv_sec  = 1,                                .it_value.tv_nsec = 0,                                .it_interval.tv_sec  = 1,                                .it_interval.tv_nsec = 0                            };    printf("Simple Threading Timer - thread-id: %d\n", gettid());    sev.sigev_notify = SIGEV_THREAD;    sev.sigev_notify_function = &expired;    sev.sigev_value.sival_ptr = &eventData;    /* 創(chuàng)建定時(shí)器 */    res = timer_create(CLOCK_REALTIME, &sev, &timerId);    if (res != 0){        fprintf(stderr, "Error timer_create: %s\n", strerror(errno));        exit(-1);    }    /* 啟動(dòng)定時(shí)器 */    res = timer_settime(timerId, 0, &its, NULL);    if (res != 0){        fprintf(stderr, "Error timer_settime: %s\n", strerror(errno));        exit(-1);    }    printf("Press ETNER Key to Exit\n");    while(getchar()!='\n'){}    return 0;}void expired(union sigval timer_data){    struct t_eventData *data = timer_data.sival_ptr;    printf("Timer fired %d - thread-id: %d\n", ++data->myData, gettid());}

這種方法的優(yōu)點(diǎn)是在代碼和簡(jiǎn)單調(diào)試方面用量小。缺點(diǎn)是由于到期時(shí)創(chuàng)建新線程而增加額外的開銷,因此行為不太確定。

中斷信號(hào)定時(shí)器

超時(shí)定時(shí)器通知的另一種可能性是基于 ??內(nèi)核信號(hào)??。內(nèi)核不是在每次定時(shí)器過期時(shí)創(chuàng)建一個(gè)新線程,而是向進(jìn)程發(fā)送一個(gè)信號(hào),進(jìn)程被中斷,并調(diào)用相應(yīng)的信號(hào)處理程序。

由于接收信號(hào)時(shí)的默認(rèn)操作是終止進(jìn)程(參考 ??signal?? 手冊(cè)頁),我們必須要提前設(shè)置好 Qt Creator,以便進(jìn)行正確的調(diào)試。

當(dāng)被調(diào)試對(duì)象接收到一個(gè)信號(hào)時(shí),Qt Creator 的默認(rèn)行為是:

  • 中斷執(zhí)行并切換到調(diào)試器上下文。
  • 顯示一個(gè)彈出窗口,通知用戶接收到信號(hào)。

這兩種操作都不需要,因?yàn)樾盘?hào)的接收是我們應(yīng)用程序的一部分。

Qt Creator 在后臺(tái)使用 GDB。為了防止 GDB 在進(jìn)程接收到信號(hào)時(shí)停止執(zhí)行,進(jìn)入 “工具(Tools) -> 選項(xiàng)Options” 菜單,選擇 “調(diào)試器Debugger”,并導(dǎo)航到 “本地變量和表達(dá)式Locals & Expressions”。添加下面的表達(dá)式到 “定制調(diào)試助手Debugging Helper Customization”:

handle SIG34 nostop pass

Sig 34 時(shí)不停止

Sig 34 時(shí)不停止

你可以在 ??GDB 文檔?? 中找到更多關(guān)于 GDB 信號(hào)處理的信息。

接下來,當(dāng)我們?cè)谛盘?hào)處理程序中停止時(shí),我們要抑制每次接收到信號(hào)時(shí)通知我們的彈出窗口:

Signal 34 彈出窗口

Signal 34 彈出窗口

為此,導(dǎo)航到 “GDB” 標(biāo)簽并取消勾選標(biāo)記的復(fù)選框:

定時(shí)器信號(hào)窗口

定時(shí)器信號(hào)窗口

現(xiàn)在你可以正確的調(diào)試 ??signal_interrupt_timer??。真正的信號(hào)定時(shí)器的實(shí)施會(huì)更復(fù)雜一些:

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>#include <signal.h>#include <time.h>#include <unistd.h>#include <errno.h>#include <string.h>#define UNUSED(x) (void)(x)static void handler(int sig, siginfo_t *si, void *uc);pid_t gettid(void);struct t_eventData{    int myData;};int main(){    int res = 0;    timer_t timerId = 0;    struct sigevent sev = { 0 };    struct t_eventData eventData = { .myData = 0 };    /* 指定收到信號(hào)時(shí)的操作 */    struct sigaction sa = { 0 };    /* 指定啟動(dòng)延時(shí)的時(shí)間和間隔時(shí)間 */    struct itimerspec its = {   .it_value.tv_sec  = 1,                                .it_value.tv_nsec = 0,                                .it_interval.tv_sec  = 1,                                .it_interval.tv_nsec = 0                            };    printf("Signal Interrupt Timer - thread-id: %d\n", gettid());    sev.sigev_notify = SIGEV_SIGNAL; // Linux-specific    sev.sigev_signo = SIGRTMIN;    sev.sigev_value.sival_ptr = &eventData;    /* 創(chuàng)建定時(shí)器 */    res = timer_create(CLOCK_REALTIME, &sev, &timerId);    if ( res != 0){        fprintf(stderr, "Error timer_create: %s\n", strerror(errno));        exit(-1);    }    /* 指定信號(hào)和處理程序 */    sa.sa_flags = SA_SIGINFO;    sa.sa_sigaction = handler;    /* 初始化信號(hào) */    sigemptyset(&sa.sa_mask);    printf("Establishing handler for signal %d\n", SIGRTMIN);    /* 注冊(cè)信號(hào)處理程序 */    if (sigaction(SIGRTMIN, &sa, NULL) == -1){        fprintf(stderr, "Error sigaction: %s\n", strerror(errno));        exit(-1);    }    /* 啟動(dòng)定時(shí)器 */    res = timer_settime(timerId, 0, &its, NULL);    if ( res != 0){        fprintf(stderr, "Error timer_settime: %s\n", strerror(errno));        exit(-1);    }    printf("Press ENTER to Exit\n");    while(getchar()!='\n'){}    return 0;}static voidhandler(int sig, siginfo_t *si, void *uc){    UNUSED(sig);    UNUSED(uc);    struct t_eventData *data = (struct t_eventData *) si->_sifields._rt.si_sigval.sival_ptr;    printf("Timer fired %d - thread-id: %d\n", ++data->myData, gettid());}

與線程定時(shí)器相比,我們必須初始化信號(hào)并注冊(cè)一個(gè)信號(hào)處理程序。這種方法性能更好,因?yàn)樗粫?huì)導(dǎo)致創(chuàng)建額外的線程。因此,信號(hào)處理程序的執(zhí)行也更加確定。缺點(diǎn)顯然是正確調(diào)試需要額外的配置工作。

總結(jié)

本文中描述的兩種方法都是接近內(nèi)核的定時(shí)器的實(shí)現(xiàn)。不過,即使 ??timer_create(...)?? 函數(shù)是 POSIX 規(guī)范的一部分,由于數(shù)據(jù)結(jié)構(gòu)的細(xì)微差別,也不可能在 FreeBSD 系統(tǒng)上編譯樣例代碼。除了這個(gè)缺點(diǎn)之外,這種實(shí)現(xiàn)還為通用計(jì)時(shí)應(yīng)用程序提供了細(xì)粒度控制。

責(zé)任編輯:龐桂玉 來源: Linux中國
相關(guān)推薦

2018-11-02 08:10:58

Linuxsystemd定時(shí)器

2009-11-11 10:14:10

linux定時(shí)器操作系統(tǒng)

2021-08-11 10:10:26

Linux定時(shí)器數(shù)組

2021-08-03 14:33:53

cron定時(shí)器Linux命令

2010-03-17 12:37:51

Python定時(shí)器

2023-12-11 09:50:35

Linux定時(shí)器

2022-11-11 14:55:14

Linuxcron

2010-07-28 15:56:22

FlexTimer定時(shí)

2011-02-23 10:20:45

2009-04-12 08:51:50

Symbian諾基亞移動(dòng)OS

2021-03-31 08:33:17

SysTick定時(shí)器SysTick定時(shí)器

2013-07-29 10:10:40

TCP協(xié)議TCP定時(shí)器TCP

2011-04-21 10:49:28

Linux時(shí)間定時(shí)器

2022-11-02 11:40:16

Flowable定時(shí)器流程

2024-06-03 00:00:20

.NET定時(shí)器

2023-08-02 09:26:03

軟件定時(shí)器鴻蒙

2017-02-28 17:18:34

Linux驅(qū)動(dòng)技術(shù)內(nèi)核定時(shí)器

2023-11-01 11:13:58

Linux信號(hào)處理定時(shí)器

2023-02-28 18:09:53

Javascript定時(shí)器

2014-12-09 16:30:18

TCP定時(shí)器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)