Linux下應用層定時器原本有好幾種,大夥能夠去搜索其餘帖子博客,這裏我主要描述我在使用setitimer時候遇到的問題,話很少說,直接上代碼吧
linux
// lock_timmer_test.cpp
ios
#include <iostream> #include <sys/time.h> #include <signal.h> #include <linux/types.h> #include <sched.h> #include <pthread.h> using namespace std; //互斥鎖 class MutexLock { public: MutexLock(){ pthread_mutex_init(&m_stMutex, NULL); } ~MutexLock(){ pthread_mutex_destroy(&m_stMutex); } void lock(){ pthread_mutex_lock(&m_stMutex);} int unlock() {return pthread_mutex_unlock(&m_stMutex); } bool trylock(){ return pthread_mutex_trylock(&m_stMutex) == 0;} pthread_mutex_t* getMutexPtr(){ return &m_stMutex;} private: pthread_mutex_t m_stMutex; }; MutexLock test_mutex; int timestep = 1; //定時器的時間間隔 //五秒切換插入map順序 void timeout_cb(int sig) { test_mutex.lock(); std::cout<<" timer lock : "<<std::endl; test_mutex.unlock(); } //開啓定時器 void set_timer() { struct sigaction sigact; sigact.sa_flags = 0; sigact.sa_handler = timeout_cb; // 設置定時器的回調函數 sigemptyset(&sigact.sa_mask); sigaction(SIGALRM, &sigact, NULL); // //結構成員it_value指定首次定時的時間, // // 結構成員it_interval指定下次定時的時間 // // 定時器工做時,先將it_value的時間值減到0, // // 發送一個信號,再將it_value賦值爲it_interval的值,從新開始定時,如此反覆。 struct itimerval itv; itv.it_interval.tv_sec = timestep; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = timestep; itv.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &itv, NULL); } int main(int argc, char const *argv[]) { set_timer(); while(true) { // test_mutex.lock(); // std::cout<<" main lock"<<std::endl; // test_mutex.unlock(); } return 0; }
編譯:g++ lock_timmer_test.cpp 運行: ./a.out函數
運行結果證實:的確每隔timestep,回調函數就會被調用,執行特定任務學習
回調函數作的操做複雜後,可能因爲調度問題或者是我本身代碼沒寫好仍是其餘緣由,在本例中,會出現死鎖問題,查了相應的資料,有人建議回調函數不要太複雜,可能因爲CPU調度問題和定時事件過短的而形成不肯定因素。
ui
因此在使用setitimer()的時候,咱們儘可能不要讓回調函數作過於複雜的操做,最好只是作某些標誌位的置位操做就好。spa
詳情參見例四。
線程
#include <iostream> #include <sys/time.h> #include <signal.h> #include <linux/types.h> #include <sched.h> #include <pthread.h> using namespace std; //互斥鎖 class MutexLock { public: MutexLock(){ pthread_mutex_init(&m_stMutex, NULL); } ~MutexLock(){ pthread_mutex_destroy(&m_stMutex); } void lock(){ pthread_mutex_lock(&m_stMutex);} int unlock() {return pthread_mutex_unlock(&m_stMutex); } bool trylock(){ return pthread_mutex_trylock(&m_stMutex) == 0;} pthread_mutex_t* getMutexPtr(){ return &m_stMutex;} private: pthread_mutex_t m_stMutex; }; MutexLock test_mutex; int timestep = 1; //五秒切換插入map順序 void timeout_cb(int sig) { test_mutex.lock(); std::cout<<" timer lock : "<<std::endl; test_mutex.unlock(); } //五秒切換插入map順序 void timeout_cb2(int sig) { test_mutex.lock(); std::cout<<" timer2 lock : "<<std::endl; test_mutex.unlock(); } void set_timer() { struct sigaction sigact; sigact.sa_flags = 0; sigact.sa_handler = timeout_cb; //定時器回調函數 sigemptyset(&sigact.sa_mask); sigaction(SIGALRM, &sigact, NULL); // //結構成員it_value指定首次定時的時間, // // 結構成員it_interval指定下次定時的時間 // // 定時器工做時,先將it_value的時間值減到0, // // 發送一個信號,再將it_value賦值爲it_interval的值,從新開始定時,如此反覆。 struct itimerval itv; itv.it_interval.tv_sec = 2*timestep; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = 2*timestep; itv.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &itv, NULL); } //設置uuid五秒切換插入順序的定時器 void set_timer2() { struct sigaction sigact; sigact.sa_flags = 0; sigact.sa_handler = timeout_cb2; sigemptyset(&sigact.sa_mask); sigaction(SIGALRM, &sigact, NULL); // //結構成員it_value指定首次定時的時間, // // 結構成員it_interval指定下次定時的時間 // // 定時器工做時,先將it_value的時間值減到0, // // 發送一個信號,再將it_value賦值爲it_interval的值,從新開始定時,如此反覆。 struct itimerval itv; itv.it_interval.tv_sec = timestep; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = timestep; itv.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &itv, NULL); } int main(int argc, char const *argv[]) { set_timer(); set_timer2(); while(true) { // test_mutex.lock(); // std::cout<<" main lock"<<std::endl; // test_mutex.unlock(); } return 0; }
運行結果:code
從運行結果中能夠看出,只有第二個定時器在運行,第一個被覆蓋了,這對於咱們想要同時設置兩種定時器的需求,貌似得不到解決(知識點的侷限,應該是咱們代碼有問題,還請大牛解答)。事件
因此針對須要設置多個定時器,我最後推薦使用select,或者使用libevent庫中的定時器,具體參見例五,libevent的Timmer。get
#include <iostream> #include <sys/time.h> #include <signal.h> #include <linux/types.h> #include <sched.h> #include <pthread.h> using namespace std; //互斥鎖 class MutexLock { public: MutexLock(){ pthread_mutex_init(&m_stMutex, NULL); } ~MutexLock(){ pthread_mutex_destroy(&m_stMutex); } void lock(){ pthread_mutex_lock(&m_stMutex);} int unlock() {return pthread_mutex_unlock(&m_stMutex); } bool trylock(){ return pthread_mutex_trylock(&m_stMutex) == 0;} pthread_mutex_t* getMutexPtr(){ return &m_stMutex;} private: pthread_mutex_t m_stMutex; }; MutexLock test_mutex; int timestep = 1; bool time_is_now = false; //五秒切換插入map順序 void timeout_cb(int sig) { time_is_now = !time_is_now; } void set_timer() { struct sigaction sigact; sigact.sa_flags = 0; sigact.sa_handler = timeout_cb; //定時器回調函數 sigemptyset(&sigact.sa_mask); sigaction(SIGALRM, &sigact, NULL); // //結構成員it_value指定首次定時的時間, // // 結構成員it_interval指定下次定時的時間 // // 定時器工做時,先將it_value的時間值減到0, // // 發送一個信號,再將it_value賦值爲it_interval的值,從新開始定時,如此反覆。 struct itimerval itv; itv.it_interval.tv_sec = 2*timestep; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = 2*timestep; itv.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &itv, NULL); } void* lokc_unlock(void * arg) { while(true) { if(time_is_now) { test_mutex.lock(); std::cout<<" timer lock : "<<std::endl; test_mutex.unlock(); time_is_now = false;// 置位 } } } int main(int argc, char const *argv[]) { set_timer(); pthread_t autorecv_child_thread; int res; if((res=pthread_create(&autorecv_child_thread,NULL,lokc_unlock, NULL))!=0) { std::cout<<"111111111111111"<<std::endl; return -1; } if( (res = pthread_detach(autorecv_child_thread) ) != 0 ) { std::cout<<"2222222222222222"<<std::endl; return -1; } while(true) { usleep(100000); test_mutex.lock(); std::cout<<" main lock"<<std::endl; test_mutex.unlock(); } return 0; }
運行結果:
從運行結果中能夠看出: 定時器回調函數只作簡單任務,複雜任務交由子線程處理,這樣不會出什麼問題。
當須要多個定時任務同時定時操做的時候,由於本人暫時尚未找到setitimer的正確用法,所以不得不借用libevent的Timmer來實現,固然直接用select也能夠,能夠去搜索相應資料學習。
#include <iostream> #include <sys/time.h> #include <signal.h> #include <linux/types.h> #include <sched.h> #include <pthread.h> #include <event2/event.h> #include <event2/thread.h> #include <event2/event-config.h> using namespace std; //互斥鎖 class MutexLock { public: MutexLock(){ pthread_mutex_init(&m_stMutex, NULL); } ~MutexLock(){ pthread_mutex_destroy(&m_stMutex); } void lock(){ pthread_mutex_lock(&m_stMutex);} int unlock() {return pthread_mutex_unlock(&m_stMutex); } bool trylock(){ return pthread_mutex_trylock(&m_stMutex) == 0;} pthread_mutex_t* getMutexPtr(){ return &m_stMutex;} private: pthread_mutex_t m_stMutex; }; MutexLock test_mutex; int timestep = 1; //五秒切換插入map順序 void timeout_cb(int fd, short event, void *params) { test_mutex.lock(); std::cout<<" timmer1 lock"<<std::endl; test_mutex.unlock(); } void timeout_cb2(int fd, short event, void *params) { test_mutex.lock(); std::cout<<" timmer2 lock"<<std::endl; test_mutex.unlock(); } void* lokc_unlock(void * arg) { event_base* base = event_base_new(); struct event *timeout = NULL; struct timeval tv = {timestep, 0}; timeout = event_new(base, -1, EV_PERSIST, timeout_cb, NULL); evtimer_add(timeout, &tv); struct event *timeout2 = NULL; struct timeval tv2 = {2*timestep, 0}; timeout2 = event_new(base, -1, EV_PERSIST, timeout_cb2, NULL); evtimer_add(timeout2, &tv2); event_base_dispatch(base); event_base_free(base); } int main(int argc, char const *argv[]) { pthread_t autorecv_child_thread; int res; if((res=pthread_create(&autorecv_child_thread,NULL,lokc_unlock, NULL))!=0) { std::cout<<"111111111111111"<<std::endl; return -1; } if( (res = pthread_detach(autorecv_child_thread) ) != 0 ) { std::cout<<"2222222222222222"<<std::endl; return -1; } while(true) { } return 0; }
運行結果:
從最後結果中看,本人仍是比較推薦使用libevent這種庫,畢竟使用簡單,功能強大。
ps:固然對於setitimer()來講,它支持延遲開啓定時器,即itimerval 的 it_intercal 和it_value的含義,libevent對於相應的支持就須要各位本身動腦筋想辦法了。(歡迎各位指教)