演示如何建立 POSIX 相容的間隔定時器
導讀 | 這是一個演示如何建立 POSIX 相容的間隔定時器的教程。 |
對開發人員來說,定時某些事件是一項常見任務。定時器的常見場景是看門狗、任務的迴圈執行,或在特定時間安排事件。在這篇文章中,我將演示如何使用 timer_create(…) 建立一個 POSIX 相容的間隔定時器。
我使用 Qt Creator 作為該樣例的 IDE。為了在 Qt Creator 執行和除錯樣例程式碼,請克隆 GitHub 上的倉庫,開啟 Qt Creator,在 “檔案File -> 開啟檔案或專案……Open File or Project…” 並選擇 “CMakeLists.txt”:
在 Qt Creator 中開啟專案
選擇工具鏈之後,點選 “配置專案Configure Project”。這個專案包括三個獨立的樣例(我們在這篇文章中將只會用到其中的兩個)。使用綠色標記出來的選單,可以在每個樣例的配置之間切換,併為每個樣例啟用在終端執行 “在終端中執行Run in terminal”(用黃色標記)。當前用於構建和除錯的活動示例可以透過左下角的“除錯Debug” 按鈕進行選擇(參見下面的橙色標記)。
專案配置
讓我們看看 simple_threading_timer.c 樣例。這是最簡單的一個。它展示了一個呼叫了超時函式 expired 的間隔定時器是如何被建立的。在每次過期時,都會建立一個新的執行緒,在其中呼叫函式 expired:
#include #include #include #include #include #include #include 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 指定了過期時要執行的操作 */ struct sigevent sev = { 0 }; /* 指定啟動延時時間和間隔時間 * 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; /* 建立定時器 */ res = timer_create(CLOCK_REALTIME, &sev, &timerId); if (res != 0){ fprintf(stderr, "Error timer_create: %s\n", strerror(errno)); exit(-1); } /* 啟動定時器 */ 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()); }
這種方法的優點是在程式碼和簡單除錯方面用量小。缺點是由於到期時建立新執行緒而增加額外的開銷,因此行為不太確定。
超時定時器通知的另一種可能性是基於 核心訊號。核心不是在每次定時器過期時建立一個新執行緒,而是向程式傳送一個訊號,程式被中斷,並呼叫相應的訊號處理程式。
由於接收訊號時的預設操作是終止程式(參考 signal 手冊頁),我們必須要提前設定好 Qt Creator,以便進行正確的除錯。
當被除錯物件接收到一個訊號時,Qt Creator 的預設行為是:
- 中斷執行並切換到偵錯程式上下文。
- 顯示一個彈出視窗,通知使用者接收到訊號。
這兩種操作都不需要,因為訊號的接收是我們應用程式的一部分。
Qt Creator 在後臺使用 GDB。為了防止 GDB 在程式接收到訊號時停止執行,進入 “工具Tools -> 選項Options” 選單,選擇 “偵錯程式Debugger”,並導航到 “本地變數和表示式Locals & Expressions”。新增下面的表示式到 “定製除錯助手Debugging Helper Customization”:
handle SIG34 nostop pass
Sig 34 時不停止
你可以在 GDB 文件 中找到更多關於 GDB 訊號處理的資訊。
接下來,當我們在訊號處理程式中停止時,我們要抑制每次接收到訊號時通知我們的彈出視窗:
Signal 34 彈出視窗
為此,導航到 “GDB” 標籤並取消勾選標記的核取方塊:
定時器訊號視窗
現在你可以正確的除錯 signal_interrupt_timer。真正的訊號定時器的實施會更復雜一些:
#include #include #include #include #include #include #include #include #include #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 }; /* 指定收到訊號時的操作 */ struct sigaction sa = { 0 }; /* 指定啟動延時的時間和間隔時間 */ 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; /* 建立定時器 */ res = timer_create(CLOCK_REALTIME, &sev, &timerId); if ( res != 0){ fprintf(stderr, "Error timer_create: %s\n", strerror(errno)); exit(-1); } /* 指定訊號和處理程式 */ sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = handler; /* 初始化訊號 */ sigemptyset(&sa.sa_mask); printf("Establishing handler for signal %d\n", SIGRTMIN); /* 註冊訊號處理程式 */ if (sigaction(SIGRTMIN, &sa, NULL) == -1){ fprintf(stderr, "Error sigaction: %s\n", strerror(errno)); exit(-1); } /* 啟動定時器 */ 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 void handler(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()); }
與執行緒定時器相比,我們必須初始化訊號並註冊一個訊號處理程式。這種方法效能更好,因為它不會導致建立額外的執行緒。因此,訊號處理程式的執行也更加確定。缺點顯然是正確除錯需要額外的配置工作。
本文中描述的兩種方法都是接近核心的定時器的實現。不過,即使 timer_create(…) 函式是 POSIX 規範的一部分,由於資料結構的細微差別,也不可能在 FreeBSD 系統上編譯樣例程式碼。除了這個缺點之外,這種實現還為通用計時應用程式提供了細粒度控制。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2934508/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- linux 如何建立定時任務?crontab -e 定時任務使用的時間是系統時間Linux
- MyBatis自動設定建立時間和更新時間MyBatis
- 如何修改Fiori Launchpad裡Tile計數呼叫的時間間隔
- 關於MySql 設定一個間隔時間 執行一個事件MySql事件
- 如何建立systemd定時任務
- 如何使用SQL計算寶寶每次吃奶的時間間隔(文末含PPT)SQL
- 建立時間和保持時間
- 好用的時間跟蹤定時器:Eon Timer for Mac定時器Mac
- [20200402]增量檢查點時間間隔.txt
- Libev——ev_timer 相對時間定時器定時器
- 建立 MQTT 連線時如何設定引數?MQQT
- GPU虛擬機器建立時間深度優化GPU虛擬機優化
- 如何在 Ubuntu 上設定時間同步Ubuntu
- mongodb中如何設定當前時間?MongoDB
- 如何建立一個可靠穩定的Web伺服器Web伺服器
- win10桌面圖示間隔怎麼調整_win10桌面圖示間隔如何設定Win10
- 定時器以及定時器的幾個案例定時器
- element-ui 時間選擇器設定時間選擇範圍UI
- win10要如何設定更新時間_win10怎麼設定更新時間Win10
- [20211203]演示job啟動時間改變的情況.txt
- 建立帶過期時間的map
- win10 如何修改更新重啟時間 win10如何設定更新時間Win10
- GPU虛擬機器建立時間深度最佳化GPU虛擬機
- win10系統如何設定360瀏覽器相容模式Win10瀏覽器模式
- 雲伺服器Linux系統設定時間同步設定伺服器Linux
- 如何使用時間機器備份您的MacMac
- MySQL實現當前資料表的所有時間都增加或減少指定的時間間隔(推薦)MySql
- Linux時間設定系統時間、硬體時間和時間服務Linux
- Android之TextView設定drawableRight等圖片文字間隔AndroidTextView
- 機器學習之支援向量與間隔機器學習
- 如何給localStorage設定一個過期時間?
- Linux如何檢視系統/伺服器的執行時間及啟動時間?Linux伺服器
- 360極速瀏覽器相容模式怎麼設定 360極速瀏覽器相容模式設定方法瀏覽器模式
- Git檢視分支建立時間Git
- 通過定時器、時間分片、Web Worker優化長任務定時器Web優化
- Qt中利用定時器QTimer實時顯示當前日期和時間QT定時器
- win10如何設定自動更新時間 win10時間不自動同步Win10
- 【java】校驗當前時間是否在規定的時間內Java