Ubuntu16.04應用程序編程中關於精準定時POSIX和SIGNAL的使用詳解

參考1:https://blog.csdn.net/lee244868149/article/details/38710149

參考2:https://blog.csdn.net/weixin_34228387/article/details/86405426

需求:

       在寫嵌入式軟件的時候,需要用到近乎us級別的定時器來實現掃描電壓;邏輯是每nus增加nuv,從而實現掃描電壓的過程。除了定時器還用到了信號。

 

理論資料 POSIX定時器:

查閱參考2

Struct timespec

{

       _time_t tv_sec;            //賦的值是以s爲單位

       _syscall_slong_t tv_nsec;      //賦的值是以ns爲單位

}

Struct itimerspec

{

       Struct timespec it_interval;   //從使能定時器開始計時的時間

       Struct timespec it_value;      //如果設定此參數,那麼定時器會以設定的參數循環執行

}

timer_create();創建一個新的定時器,放回一個唯一的定時器ID

timer_delete();刪除一個已經存在的定時器,刪除前先讓定時器停止;下面會談到如何讓定時器停止;

timer_settime();設置定時器參數;開始定時器;停止定時器都用的這個函數

timer_gettime();

timer_getoverrun();

實際應用:

int posix_timer_id;

struct itimerspec ts;

ts.it_value.tv_sec = 1;  //  1

ts.it_value.tv_ nsec = 0; //  2

ts.it_ interval.tv_sec = 1;//  3

ts.it_ interval.tv_ nsec = 0;// 4

//第1、2來設置第一次定時的時間;第2、3來設置循環定時的時間

timer_settime(posix_timer_id, 0, &ts, 0);//  5

//第5來設置定時器參數,並且開始定時器

ts.it_value.tv_sec = 0;  //  6

ts.it_value.tv_ nsec = 0; //  7

ts.it_ interval.tv_sec = 0;//  8

ts.it_ interval.tv_ nsec = 0;// 9

timer_settime(posix_timer_id, 0, &ts, 0);

//第 6、7、8、9都設置爲0時,表示停止定時器

timer_delete(posix_timer_id);//10

//第10來刪除定時器

 

理論資料 SIGNAL信號:

查閱參考1

實際應用:

//創建線程前,將signal_mask信號集從信號掩碼中移除

sigemptyset(&signal_mask);

sigaddset(&signal_mask, SIGUSR1);

sigaddset(&signal_mask, SIGTERM);

pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL);                      

 

//創建新線程, 服務器初接收函數                                            

pthread_create(&threadID_Sample, NULL, ThreadFunction, NULL);

 

//創建線程後,屏蔽signal_mask信號集;

sigemptyset(&signal_mask);

sigaddset(&signal_mask, SIGUSR1);

sigaddset(&signal_mask, SIGTERM);

pthread_sigmask(SIG_BLOCK, &signal_mask, NULL);

 

/************************* ThreadFunction線程函數內*********************************/

//初始化信號參數

act.sa_handler = StartSample_IT;

act.sa_flags = 0;

sigemptyset(&act.sa_mask);

sigaction(SIGUSR1, &act, NULL);

 

//用來指定定時器到期時要產生的異步通知

memset(&sev, 0, sizeof(sev));

sev.sigev_signo = SIGUSR1;

sev.sigev_notify = SIGEV_SIGNAL;//SIGEV_SIGNAL(產生信號) SIGEV_NONE(不處理) SIGEV_THREAD(新線程處理)SIGEV_THREAD_ID(指定線程處理)

 

//創建定時器

timer_create(CLOCK_REALTIME, &sev, &posix_timer_id);

 

//設置定時器並啓動

ts.it_value.tv_sec = ns / 1000000000;

ts.it_value.tv_nsec = ns % 1000000000;

printf("ts.it_value.tv_sec:%d\n", ts.it_value.tv_sec);

printf("ts.it_value.tv_nsec:%d\n", ts.it_value.tv_nsec);

timer_settime(posix_timer_id, 0, &ts, 0);

 

ts.it_value.tv_sec = 0;

ts.it_value.tv_nsec = 0;

timer_settime(posix_timer_id, 0, &ts, 0);//定時器停止

timer_delete(posix_timer_id);//刪除定時器                 

pthread_cancel(threadID_Sample);

pthread_join(threadID_Sample, NULL);//回收線程

 

在整個過程中遇到的問題包括:

  1. 信號產生後會傳給每個線程,若想只讓子線程接收信號,那麼就要在父線程中屏蔽該信號。
  2. 在父線程中創建子線程時候,子線程會繼承父線程屏蔽的信號,所以在創建線程前要移除被屏蔽的信號。
  3. 不用定時器或者線程了,就要刪除和銷燬線程
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章