1. 程式人生 > >使用SIGALRM訊號量和sleep衝突的解決辦法

使用SIGALRM訊號量和sleep衝突的解決辦法

系統中的一個模組需要頻繁的獲取系統時間,使用linux中內建的函式開銷過大,因為需要的精度不是很高(毫秒級),索性用signal函式配合setitimer實現了個簡易的全域性時鐘。

但是後來發現,SIGALRM的中斷訊號回終止sleep,因為sleep就是用SIGALRM訊號量實現的,得另想方案。

這個替代方案就是POSIX中內建的定時器:timer_create()(建立)、timer_settime()(初始化)以及timer_delete(銷燬),將自己的時間訊號處理函式用timer_create註冊為SIGUSR2,這樣就不會中斷sleep了。

POSIX定時器:timer_settime()

最強大的定時器介面來自POSIX時鐘系列,其建立、初始化以及刪除一個定時器的行動被分為三個不同的函式:timer_create()(建立定時器)、timer_settime()(初始化定時器)以及timer_delete(銷燬它)。
建立一個定時器

int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)

[cpp] view plaincopyprint?
  1. struct itimespec{ 
  2.     struct timespec it_interval;  
  3.     struct
    timespec it_value;  
  4. };  
struct itimespec{
    struct timespec it_interval; 
    struct timespec it_value; 
}; 

程序可以通過呼叫timer_create()建立特定的定時器,定時器是每個程序自己的,不是在fork時繼承的。clock_id說明定時器是基於哪個時鐘的,*timerid裝載的是被建立的定時器的ID。該函式建立了定時器,並將他的ID 放入timerid指向的位置中。引數evp指定了定時器到期要產生的非同步通知。如果evp為NULL,那麼定時器到期會產生預設的訊號,對 CLOCK_REALTIMER來說,預設訊號就是SIGALRM。如果要產生除預設訊號之外的其它訊號,程式必須將 evp->sigev_signo設定為期望的訊號碼。struct sigevent 結構中的成員evp->sigev_notify說明了定時器到期時應該採取的行動。通常,這個成員的值為SIGEV_SIGNAL,這個值說明在定時器到期時,會產生一個訊號。程式可以將成員evp->sigev_notify設為SIGEV_NONE來防止定時器到期時產生訊號。
如果幾個定時器產生了同一個訊號,處理程式可以用 evp->sigev_value來區分是哪個定時器產生了訊號。要實現這種功能,程式必須在為訊號安裝處理程式時,使用struct sigaction的成員sa_flags中的標誌符SA_SIGINFO。
clock_id取值為以下:

CLOCK_REALTIME :Systemwide realtime clock.
CLOCK_MONOTONIC:Represents monotonic time. Cannot be set.
CLOCK_PROCESS_CPUTIME_ID :High resolution per-process timer.
CLOCK_THREAD_CPUTIME_ID :Thread-specific timer.
CLOCK_REALTIME_HR :High resolution version of CLOCK_REALTIME.
CLOCK_MONOTONIC_HR :High resolution version of CLOCK_MONOTONIC.

[cpp] view plaincopyprint?
  1. struct sigevent 
  2.     int sigev_notify; //notification type
  3.     int sigev_signo; //signal number
  4.     union sigval   sigev_value; //signal valu
  5.     void (*sigev_notify_function)(union sigval) 
  6.     pthread_attr_t *sigev_notify_attributes 
  7. union sigval 
  8.     int sival_int; //integer valu
  9.     void *sival_ptr; //pointer value
struct sigevent

{
    int sigev_notify; //notification type
    int sigev_signo; //signal number
    union sigval   sigev_value; //signal valu
    void (*sigev_notify_function)(union sigval)
    pthread_attr_t *sigev_notify_attributes
}

union sigval

{

    int sival_int; //integer valu
    void *sival_ptr; //pointer value

}


通過將evp->sigev_notify設定為如下值來定製定時器到期後的行為:
SIGEV_NONE:什麼都不做,只提供通過timer_gettime和timer_getoverrun查詢超時資訊。
SIGEV_SIGNAL: 當定時器到期,核心會將sigev_signo所指定的訊號傳送給程序。在訊號處理程式中,si_value會被設定會sigev_value。
SIGEV_THREAD: 當定時器到期,核心會(在此程序內)以sigev_notification_attributes為執行緒屬性建立一個執行緒,並且讓它執行sigev_notify_function,傳入sigev_value作為為一個引數。
啟動一個定時器

timer_create()所建立的定時器並未啟動。要將它關聯到一個到期時間以及啟動時鐘週期,可以使用timer_settime()。

int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspect *ovalue);

如同settimer(),it_value用於指定當前的定時器到期時間。當定時器到期,it_value的值會被更新成it_interval 的值。如果it_interval的值為0,則定時器不是一個時間間隔定時器,一旦it_value到期就會回到未啟動狀態。timespec的結構提供了納秒級解析度:

[cpp] view plaincopyprint?
  1. struct timespec{ 
  2.     time_t tv_sec; 
  3.     long tv_nsec;  
  4. }; 
struct timespec{

    time_t tv_sec;

    long tv_nsec; 

};

如果flags的值為TIMER_ABSTIME,則value所指定的時間值會被解讀成絕對值(此值的預設的解讀方式為相對於當前的時間)。這個經修改的行為可避免取得當前時間、計算“該時間”與“所期望的未來時間”的相對差額以及啟動定時器期間造成競爭條件。
如果ovalue的值不是NULL,則之前的定時器到期時間會被存入其所提供的itimerspec。如果定時器之前處在未啟動狀態,則此結構的成員全都會被設定成0。

獲得一個活動定時器的剩餘時間:

int timer_gettime(timer_t timerid,struct itimerspec *value);

取得一個定時器的超限執行次數:

有可能一個定時器到期了,而同一定時器上一次到期時產生的訊號還處於掛起狀態。在這種情況下,其中的一個訊號可能會丟失。這就是定時器超限。程式可以通過呼叫timer_getoverrun來確定一個特定的定時器出現這種超限的次數。定時器超限只能發生在同一個定時器產生的訊號上。由多個定時器,甚至是那些使用相同的時鐘和訊號的定時器,所產生的訊號都會排隊而不會丟失。

int timer_getoverrun(timer_t timerid);

執行成功時,timer_getoverrun()會返回定時器初次到期與通知程序(例如通過訊號)定時器已到期之間額外發生的定時器到期次數。舉例來說,在我們之前的例子中,一個1ms的定時器運行了10ms,則此呼叫會返回9。如果超限執行的次數等於或大於DELAYTIMER_MAX,則此呼叫會返回DELAYTIMER_MAX。

執行失敗時,此函式會返回-1並將errno設定會EINVAL,這個唯一的錯誤情況代表timerid指定了無效的定時器。

刪除一個定時器:

int timer_delete (timer_t timerid);

一次成功的timer_delete()呼叫會銷燬關聯到timerid的定時器並且返回0。執行失敗時,此呼叫會返回-1並將errno設定會 EINVAL,這個唯一的錯誤情況代表timerid不是一個有效的定時器。

例1:

[cpp] view plaincopyprint?
  1. void handle() 
  2.     time_t t; 
  3.     char p[32]; 
  4.     time(&t); 
  5.     strftime(p, sizeof(p), "%T", localtime(&t)); 
  6.     printf("time is %s\n", p); 
  7. int main() 
  8.     struct sigevent evp; 
  9.     struct itimerspec ts; 
  10.     timer_t timer; 
  11.     int ret; 
  12.     evp.sigev_value.sival_ptr = &timer; 
  13.     evp.sigev_notify = SIGEV_SIGNAL; 
  14.     evp.sigev_signo = SIGUSR1; 
  15.     signal(SIGUSR1, handle); 
  16.     ret = timer_create(CLOCK_REALTIME, &evp, &timer); 
  17.     if( ret ) 
  18.         perror("timer_create"); 
  19.     ts.it_interval.tv_sec = 1; 
  20.     ts.it_interval.tv_nsec = 0; 
  21.     ts.it_value.tv_sec = 3; 
  22.     ts.it_value.tv_nsec = 0; 
  23.     ret = timer_settime(timer, 0, &ts, NULL); 
  24.     if( ret ) 
  25.     perror("timer_settime"); 
  26.     while(1); 
void handle()
{
    time_t t;
    char p[32];

    time(&t);
    strftime(p, sizeof(p), "%T", localtime(&t));

    printf("time is %s\n", p);
}



int main()
{
    struct sigevent evp;
    struct itimerspec ts;
    timer_t timer;
    int ret;

    evp.sigev_value.sival_ptr = &timer;
    evp.sigev_notify = SIGEV_SIGNAL;
    evp.sigev_signo = SIGUSR1;
    signal(SIGUSR1, handle);

    ret = timer_create(CLOCK_REALTIME, &evp, &timer);
    if( ret )
        perror("timer_create");

    ts.it_interval.tv_sec = 1;
    ts.it_interval.tv_nsec = 0;
    ts.it_value.tv_sec = 3;
    ts.it_value.tv_nsec = 0;

    ret = timer_settime(timer, 0, &ts, NULL);
    if( ret )
    perror("timer_settime");

    while(1);
}


例2:

[cpp] view plaincopyprint?
  1. void handle(union sigval v) 
  2.     time_t t; 
  3.     char p[32]; 
  4.     time(&t); 
  5.     strftime(p, sizeof(p), "%T", localtime(&t)); 
  6.     printf("%s thread %lu, val = %d, signal captured.\n", p, pthread_self(), v.sival_int); 
  7.     return
  8. int main() 
  9.     struct sigevent evp; 
  10.     struct itimerspec ts; 
  11.     timer_t timer; 
  12.     int ret; 
  13.     memset (&evp, 0, sizeof (evp)); 
  14.     evp.sigev_value.sival_ptr = &timer; 
  15.     evp.sigev_notify = SIGEV_THREAD; 
  16.     evp.sigev_notify_function = handle; 
  17.     evp.sigev_value.sival_int = 3; //作為handle()的引數
  18.     ret = timer_create(CLOCK_REALTIME, &evp, &timer); 
  19.     if( ret) 
  20.         perror("timer_create"); 
  21.     ts.it_interval.tv_sec = 1; 
  22.     ts.it_interval.tv_nsec = 0; 
  23.     ts.it_value.tv_sec = 3; 
  24.     ts.it_value.tv_nsec = 0; 
  25.     ret = timer_settime(timer, TIMER_ABSTIME, &ts, NULL); 
  26.     if( ret ) 
  27.         perror("timer_settime"); 
  28.     while(1); 
void handle(union sigval v)
{
    time_t t;
    char p[32];

    time(&t);
    strftime(p, sizeof(p), "%T", localtime(&t));

    printf("%s thread %lu, val = %d, signal captured.\n", p, pthread_self(), v.sival_int);
    return;
}



int main()
{
    struct sigevent evp;
    struct itimerspec ts;
    timer_t timer;
    int ret;

    memset (&evp, 0, sizeof (evp));
    evp.sigev_value.sival_ptr = &timer;
    evp.sigev_notify = SIGEV_THREAD;
    evp.sigev_notify_function = handle;
    evp.sigev_value.sival_int = 3; //作為handle()的引數

    ret = timer_create(CLOCK_REALTIME, &evp, &timer);
    if( ret)
        perror("timer_create");

    ts.it_interval.tv_sec = 1;
    ts.it_interval.tv_nsec = 0;
    ts.it_value.tv_sec = 3;
    ts.it_value.tv_nsec = 0;

    ret = timer_settime(timer, TIMER_ABSTIME, &ts, NULL);
    if( ret )
        perror("timer_settime");

    while(1);
}

相關推薦

使用SIGALRM訊號sleep衝突解決辦法

系統中的一個模組需要頻繁的獲取系統時間,使用linux中內建的函式開銷過大,因為需要的精度不是很高(毫秒級),索性用signal函式配合setitimer實現了個簡易的全域性時鐘。 但是後來發現,SIGALRM的中斷訊號回終止sleep,因為sleep就是用SIGALRM

ScrollView(Listview)Viewpager(banner)的衝突解決辦法

原文地址:https://blog.csdn.net/qq_36255612/article/details/77987947 其實就是在onInterceptTouchEvent中做處理即可: 也可以直接使用下面的自定義: public class MyScrollView exte

同一個dom上加單擊事件雙擊事件的衝突解決辦法,雙擊事件方法進不去

data() { return { TimeFn:''//定義公用變數}} $(".proManage fieldset ul li").dblclick(function(){//雙擊播放專案 //雙擊事件執行的方法   this.TimeFn = ""}) $(".proManage

git 開發注意問題衝突解決辦法

1、分支切換,一般需要將當前分支全部提交。如不提交,可以stash(暫存),考慮當前分支未提交部分是否需要merge到目標分支,如果需要,直接切換,如果不要先提交或者暫存。 git checkout [branch-name]  如果[branch-name] 遠端分支有,

Django忘記管理員賬號密碼的解決辦法

com server superuser 技術分享 tor reat n) 一個 min 看著Django的教程學習搭建網站,結果忘記第一次創建的賬號和密碼了。結果搭建成功以後,一直無法登陸到管理頁面,進行不下去了。 如圖所示: 在網上找了很多的方法都不行,最後使用新建一個

HttpWebRequest的GetResponse或GetRequestStream偶爾超時 + 總結各種超時死掉的可能相應的解決辦法

遇到 padding conn 計算 動作 spa 多次 獲得 archive 用C#模擬網頁登陸,其中去請求幾個頁面,會發起對應的http的請求request,其中keepAlive設置為true,提交請求後,然後會有對應的response: resp = (HttpW

for批處理skip參數不支持變延遲!n!的解決辦法

+= txt amp lse AS 參數 處理 off 變量延遲 a.txt 文件a第1行 文件a第2行 文件a第3行 b.txt 文件b第1行 文件b第2行 文件b第3行 合並ab .bat @echo off REM 把兩個文件逐

alembic常用命令經典錯誤解決辦法

經典 bsp ima 分享 技術分享 nbsp 技術 經典錯誤 bic alembic常用命令和經典錯誤解決辦法

Pycharm載入第三方外掛失敗方法(關鍵字:Nothing to show)安裝失敗解決辦法

一、修復外掛顯示錯誤,共3個步驟: 1,新增額外源:  清華:https://pypi.tuna.tsinghua.edu.cn/simple 阿里雲:http://mirrors.aliyun.com/pypi/simple/ 中國科技大學 https://pypi.mi

Linux多執行緒程式設計---執行緒間同步(互斥鎖、條件變數、訊號讀寫鎖)

本篇博文轉自http://zhangxiaoya.github.io/2015/05/15/multi-thread-of-c-program-language-on-linux/ Linux下提供了多種方式來處理執行緒同步,最常用的是互斥鎖、條件變數、訊號量和讀寫鎖。  下面是思維導

innerHTML與button事件衝突解決辦法

事情描述,我在body裡面寫了如下一個button <body> <input id="btn" type="button" value="自動生成V提高版本"> </body> 然後在js裡面獲取了這個button,然後給它新增點選事件 var b

關於mac上操作nginx的命令以及遇到的問題對應的解決辦法

1、mac上查詢nginx安裝位置 在終端輸入: nginx -V 檢視nginx版本及安裝的本地位置 ngxin -v 檢視nginx版本(此方法依然可以檢測是否安裝某一軟體,如git,hg等) 2、在Mac上用brew安裝Nginx,然後修改Nginx配置檔案,再重啟時報出如下錯

CoordinatorLayout 巢狀Recyclerview在巢狀Recyclerview滑動出現衝突解決辦法

RecyclerView巢狀RecycleView  要做一個介面,CoordinatorLayout巢狀AppBarLayout和RecyclerView來實現摺疊滑動,我的RecycleView裡面佈局較多,計劃再嵌入RecyclerView來實現,當我用到RecyclerView新增

Git程式碼衝突解決辦法

如果伺服器上的檔案發生了更改了的話,在本地更改該檔案之前未使用git pull命令的話,那麼在本地修改完該檔案後使用git pull 或者git push時會發生衝突: error: Your local changes to the following files would be overw

表單驗證——inputrequired衝突解決

1. input和required衝突解決 Question: 使用表單提交驗證必填欄位時,若同時給 input[type="file"] 新增 readonly 以及 required 屬性,則發現,required必填驗證失效,既不會提示必填,也可以成功提交。 解決方法:將 r

HashMap原理及衝突解決辦法

class HashMap<K,V> extends AbstractMap<K,V> HashMap  put() HashMap  get() 1.put()   HashMap put()方法原始碼如下:

maven依賴衝突解決辦法

  一般的開發,maven依賴衝突基本不存在,但是如果專案多,依賴複雜,就說不定了。依賴衝突說明專案依賴的某一個jar包,有多個不同的版本,至少兩個或兩個以上,對於這種問題,最直接的就是通過修改專案依賴的版本為最新的版本即可。同時,也有另一種解決辦法,就是將傳遞依賴剪除掉(低版本的那個依

hash衝突解決javahash衝突解決

其實就是四種方法的演變 1.開放定址法 具體就是把資料的標誌等的對長度取模   有三種不同的取模 線性探測再雜湊 給資料的標誌加增量,取模 平方探測再雜湊 給資料的標誌平方,取模 隨機探測再雜湊 把資料的標誌隨機化,取模   線性,平方顯然很容被人猜出規律,所以最終是隨機

Oracle資料庫安裝+漢化版PLsql+Oracle外掛,plsql連線Oracle步驟報錯解決辦法

    從https://download.csdn.net/download/fxiaoyaole/10449523 此連結下載裡面有所資源,資源包括(Oracle兩個資料庫壓縮包win64_11gR2_database_1of2, win64_11gR2_database

有關訊號PV操作的易(粗)懂(淺)理解

大概只有作業系統老師佈置的作業(要交)能讓我認真學習吧…… 訊號量Semaphore 1.有關訊號量的一些說明: 訊號量S是一個整數,S大於等於零時代表可供併發程序使用的資源實體數,但S小於零時