❶ 在線程中怎麼實現精確定時
問題一:定時器一般是以線程的方式運行的,如果能得到該線程的引用,就可以像查看Thread一樣查看定時器的運行狀態。
如果可以修改源代碼最好給他提供一個方法返回線程引用
問題二:TimerTask實現了介面Runnable,如果是以newThread(TimerTask)。
start()方式啟動就是做為一個單獨的線程運行的,如果是timeTask.run()那就是方法調用,雖然占據一個線程,但這個線程就是主線程,並沒有啟動新的線程;
既然實現線程,自然可以通過Thread的isAlive方法獲取其live狀態;
一般情況下(不發生異常),定時器會一直運行,如果JVM停止,那麼線程必然已經終止,如果JVM中只有這一個線程在運行,那麼JVM不停,這個定時器就是一定在運行中,如果JVM中還有其他線程在運行,那麼JVM不停,這個定時器有可能已經終止
PS:無論用不用線程池,線程啟動方式只有兩種(不包含mainThread):一種是繼承Thread類,然後直接同構引用調用start方法,第二種就是繼承Runnable介面,通過newThread(newMyRunnableClass())。
start()方式啟動。
無論如何,都會有一個Thread類的引用
補充:
一個tomcat只啟動一個進程,而JVM的垃圾處理器也只有一個,所以在一個工程里運行System.gc也會影響到其他工程。
❷ 怎樣在linux下實現精確定時器
linux下使用select實現精確定時器
在編寫程序時,我們經常回用到定時器。本文講述如何使用select實現超級時鍾。使用select函數,我們能實現微妙級別精度的定時器。同時,select函數也是我們在編寫非阻塞程序時經常用到的一個函數。
首先看看select函數原型如下:
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
參數說明:
slect的第一個參數nfds為fdset集合中最大描述符值加1,fdset是一個位數組,其大小限制為__FD_SETSIZE(1024),位數組的每一位代表其對應的描述符是否需要被檢查。
select的第二三四個參數表示需要關注讀、寫、錯誤事件的文件描述符位數組,這些參數既是輸入參數也是輸出參數,可能會被內核修改用於標示哪些描述符上發生了關注的事件。所以每次調用select前都需重新初始化fdset。
timeout參數為超時時間,該結構會被內核修改,其值為超時剩餘的時間。
利用select實現定時器,需要利用其timeout參數,注意到:
1)select函數使用了一個結構體timeval作為其參數。
2)select函數會更新timeval的值,timeval保持的值為剩餘時間。
如果我們指定了參數timeval的值,而將其他參數都置為0或者NULL,那麼在時間耗盡後,select函數便返回,基於這一點,我們可以利用select實現精確定時。
timeval的結構如下:
struct timeval{
long tv_sec;/*secons*
long tv_usec;/*microseconds*/
}
我們可以看出其精確到microseconds也即微妙。
一、秒級定時器
void seconds_sleep(unsigned seconds){
struct timeval tv;
tv.tv_sec=seconds;
tv.tv_usec=0;
int err;
do{
err=select(0,NULL,NULL,NULL,&tv);
}while(err<0 && errno==EINTR);
}
二、毫秒級別定時器
void milliseconds_sleep(unsigned long mSec){
struct timeval tv;
tv.tv_sec=mSec/1000;
tv.tv_usec=(mSec%1000)*1000;
int err;
do{
err=select(0,NULL,NULL,NULL,&tv);
}while(err<0 && errno==EINTR);
}
三、微妙級別定時器
void microseconds_sleep(unsigned long uSec){
struct timeval tv;
tv.tv_sec=uSec/1000000;
tv.tv_usec=uSec%1000000;
int err;
do{
err=select(0,NULL,NULL,NULL,&tv);
}while(err<0 && errno==EINTR);
}
現在我們來編寫幾行代碼看看定時效果吧。
#include <stdio.h>
#include <sys/time.h>
#include <errno.h>
int main()
{
int i;
for(i=0;i<5;++i){
printf("%d\n",i);
//seconds_sleep(1);
//milliseconds_sleep(1500);
microseconds_sleep(1900000);
}
}
註:timeval結構體中雖然指定了一個微妙級別的解析度,但內核支持的分別率往往沒有這么高,很多unix內核將超時值向上舍入成10ms的倍數。此外,加上內核調度延時現象,即定時器時間到後,內核還需要花一定時間調度相應進程的運行。因此,定時器的精度,最終還是由內核支持的分別率決定。
❸ linux alarm 能在線程中用嗎
不管是在進程還是線程,很多時候我們都會使用一些定時器之類的功能,這里就定時器在多線程的使用說一下。首先在linux編程中定時器函數有alarm()和setitimer(),alarm()可以提供一個基於秒的定時功能,而setitimer可以提供一個基於微妙的定時功能。
alarm()原型:
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
這個函數在使用上很簡單,第一次調用這個函數的時候是設置定時器的初值,下一次調用是重新設置這個值,並會返回上一次定時的剩餘時間。
setitimer()原型:
#include <sys/time.h>
int setitimer(int which, const struct itimerval *value,struct itimerval *ovalue);
這個函數使用起來稍微有點說法,首先是第一個參數which的值,這個參數設置timer的計時策略,which有三種狀態分別是:
ITIMER_REAL:使用系統時間來計數,時間為0時發出SIGALRM信號,這種定時能夠得到一個精準的定時,當然這個定時是相對的,因為到了微秒級別我們的處理器本身就不夠精確。
ITIMER_VIRTUAL:使用進程時間也就是進程分配到的時間片的時間來計數,時間為0是發出SIGVTALRM信號,這種定時顯然不夠准確,因為系統給進程分配時間片不由我們控制。
ITIMER_PROF:上面兩種情況都能夠觸發
第二個參數參數value涉及到兩個結構體:
struct itimerval {
struct timeval it_interval; /* next value */
struct timeval it_value; /* current value */
};
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
在結構體itimerval中it_value是定時器當前的值,it_interval是當it_value的為0後重新填充的值。而timeval結構體中的兩個變數就簡單了一個是秒一個是微秒。
上面是這兩個定時函數的說明,這個函數使用本不是很難,可以說是很簡單,但是碰到具體的應用的時候可能就遇到問題了,在多進程編程中使用一般不會碰到什麼問題,這里說的這些問題主要體現在多線程編程中。比如下面這個程序:
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
void sig_handler(int signo)
{
alarm(2);
printf("alarm signal\n");
}
void *pthread_func()
{
alarm(2);
while(1)
{
pause();
}
}
int main(int argc, char **argv)
{
pthread_t tid;
int retval;
signal(SIGALRM, sig_handler);
if((retval = pthread_create(&tid, NULL, pthread_func, NULL)) < 0)
{
perror("pthread_create");
exit(-1);
}
while(1)
{
printf("main thread\n");
sleep(10);
}
return 0;
}
這個程序的理想結果是:
main thread
alarm signal
alarm signal
alarm signal
alarm signal
alarm signal
main thread
可事實上並不是這樣的,它的結果是:
main pthread
alarm signal
main pthread
alarm signal
main pthread
為什麼會出現這種情況呢?是因為發送給工作線程的信號中斷的主線程的sleep,並且這個中情況隻影響主線程而不會影響到其他的工作線程。我們怎麼才能解決這種問題呢,最簡單的方法是修改這個程序,修改這個線程主線程使用alarm,工作線程使用sleep。這樣就能夠達到我們的要求,但是有時候有不能簡單的這樣操作。所以我們就需要進一步的修改我們的程序。在這里我第一個想到的是使用signal(SIGALRM, SIG_IGN),可是這個是設置整個進程對這個信號的響應方式,經過測試也確實不能完成我期望的功能,那麼怎麼辦呢?有這樣一個函數pthread_sigmask,線程中的信號屏蔽,函數的原型及相關函數為:
#include <signal.h>
int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
函數中第一個參數how有三個值SIG_BLOCK、SIG_SETMASK和SIG_UNBLOCK這里我們是用第二個值SIG_SETMASK
int sigemptyset(sigset_t *set); /*清除信號集合set*/
int sigaddset(sigset_t *set, int signum); /*添加信號signum到信號集set中*/
然後我們改造我們的程序為:
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
void sig_handler(int signo)
{
alarm(2);
printf("alarm signal\n");
}
void *pthread_func()
{
alarm(2);
while(1)
{
pause();
}
}
int main(int argc, char **argv)
{
pthread_t tid, tid_1;
int retval;
signal(SIGALRM, sig_handler);
if((retval = pthread_create(&tid, NULL, pthread_func, NULL)) < 0)
{
perror("pthread_create");
exit(-1);
}
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
pthread_sigmask(SIG_SETMASK,&sigset,NULL);
while(1)
{
printf("main pthread\n");
sleep(10);
}
return 0;
}
這個時候我們就能夠看到我們想要的結果了。
這里再附一個setitimer的使用範例:
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
struct itimerval timerval;
void sig_handler(int signo)
{
printf("alarm signal\n");
}
void *pthread_func()
{
setitimer(ITIMER_REAL, &timerval, NULL);
while(1)
{
pause();
}
}
int main(int argc, char **argv)
{
pthread_t tid;
int retval;
timerval.it_interval.tv_sec = 2;
timerval.it_interval.tv_usec = 0;
timerval.it_value.tv_sec = 2;
timerval.it_value.tv_usec = 0;
signal(SIGALRM, sig_handler);
if((retval = pthread_create(&tid, NULL, pthread_func, NULL)) < 0)
{
perror("pthread_create");
exit(-1);
}
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
pthread_sigmask(SIG_SETMASK,&sigset,NULL);
while(1)
{
printf("main thread\n");
sleep(5);
}
return 0;
}
❹ linux下的幾種時鍾和定時器機制
1. RTC(Real Time Clock)
所有PC都有RTC. 它和CPU和其他晶元獨立。它在電腦關機之後還可以正常運行。RTC可以在IRQ8上產生周期性中斷. 頻率在2Hz--8192HZ.
Linux只是把RTC用來獲取時間和日期. 當然它允許進程通過對/dev/rtc設備來對它進行編程。Kernel通過0x70和0x71 I/O埠來訪問RTC。
2. TSC(Time Stamp Counter)
80x86上的微處理器都有CLK輸入針腳. 從奔騰系列開始. 微處理器支持一個計數器. 每當一個時鍾信號來的時候. 計數器加1. 可以通過匯編指令rdtsc來得到計數器的值。通過calibrate_tsc可以獲得CPU的頻率. 它是通過計算大約5毫秒里tsc寄存器裡面的增加值來確認的。或者可以通過cat /proc/cpuinfo來獲取cpu頻率。tsc可以提供比PIT更精確的時間度量。
3. PIT(Programmable internval timer)
除了RTC和TSC. IBM兼容機提供了PIT。PIT類似微波爐的鬧鍾機制. 當時間到的時候. 提供鈴聲. PIT不是產生鈴聲. 而是產生一種特殊中斷. 叫定時器中斷或者時鍾中斷。它用來告訴內核一個間隔過去了。這個時間間隔也叫做一個滴答數。可以通過編譯內核是選擇內核頻率來確定。如內核頻率設為1000HZ,則時間間隔或滴答為1/1000=1微秒。滴答月短. 定時精度更高. 但是用戶模式的時間更短. 也就是說用戶模式下程序執行會越慢。滴答的長度以納秒形式存在tick_nsec變數裡面。PIT通過8254的0x40--0x43埠來訪問。它產生中斷號為IRQ 0.
下面是關於pIT裡面的一些宏定義:
HZ:每秒中斷數。
CLOCK_TICK_RATE:值是1,193,182. 它是8254晶元內部振盪器頻率。
LATCH:代表CLOCK_TICK_RATE和HZ的比率. 被用來編程PIT。
setup_pit_timer()如下:
spin_lock_irqsave(&i8253_lock, flags);
outb_p(0x34,0x43);
udelay(10);
outb_p(LATCH & 0xff, 0x40);
udelay(10);
outb (LATCH >> 8, 0x40);
spin_unlock_irqrestore(&i8253_lock, flags);
4. CPU Local Timer
最近的80x86架構的微處理器上的local apic提供了cpu local timer.他和pit區別在於它提供了one-shot和periodic中斷。它可以使中斷發送到特定cpu。one-shot中斷常用在實時系統裡面。
❺ 求linux毫秒級定時器的實現
1 nanosleep函數可以提供最高解析度,一般是納秒級
2 select、poll函數的定時是毫秒級,pselect是納秒級
以上三個函數都可以實現你的要求
❻ 在linux環境中,如何實現多線程中使用多個定時器,POSIX定時器可以嗎,如何用
個人解決了,以下是一個實現:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#if 1
pthread_attr_t attr;
timer_t hard_timer, software_timer;
struct sigevent hard_evp, software_evp;
static void watchdog_hard_timeout(union sigval v)
{
time_t t;
char p[32];
timer_t *q;
struct itimerspec ts;
int ret;
time(&t);
strftime(p, sizeof(p), "%T", localtime(&t));
printf("watchdog hard timeout!\n");
printf("%s thread %d, val = %u, signal captured.\n", p, (unsigned int)pthread_self(), v.sival_int);
q = (timer_t *)(v.sival_ptr);
printf("hard timer_t:%d add:%p, q:%p!\n", (int)hard_timer, &hard_timer, q);
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = 0;
ts.it_value.tv_sec = 6;
ts.it_value.tv_nsec = 0;
ret = timer_settime(*q, CLOCK_REALTIME, &ts, NULL);
if (ret != 0) {
printf("settime err(%d)!\n", ret);
}
}
static void watchdog_software_timeout(union sigval v)
{
time_t t;
char p[32];
timer_t *q;
struct itimerspec ts;
int ret;
time(&t);
strftime(p, sizeof(p), "%T", localtime(&t));
printf("watchdog software timeout!\n");
printf("%s thread %d, val = %u, signal captured.\n", p, (unsigned int)pthread_self(), v.sival_int);
q = (timer_t *)(v.sival_ptr);
printf("hard timer_t:%d add:%p, q:%p!\n", (int)hard_timer, &hard_timer, q);
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = 0;
ts.it_value.tv_sec = 10;
ts.it_value.tv_nsec = 0;
ret = timer_settime(*q, CLOCK_REALTIME, &ts, NULL);
if (ret != 0) {
printf("settime err(%d)!\n", ret);
}
}
static void dcmi_sol_pthread_attr_destroy(pthread_attr_t *attr)
{
pthread_attr_destroy(attr);
}
static int dcmi_sol_pthread_attr_init(pthread_attr_t *attr)
{
int ret;
if ((ret = pthread_attr_init(attr) != 0)) {
goto err;
}
if ((ret = pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED)) != 0) {
dcmi_sol_pthread_attr_destroy(attr);
goto err;
}
/* 設置線程的棧大小,失敗則用系統默認值 */
pthread_attr_setstacksize(attr, 128 * 1024);
return 0;
err:
printf("set ptread attr failed(ret:%d)!\n", ret);
return -1;
}
int main(void)
{
struct itimerspec ts;
int ret;
ret = dcmi_sol_pthread_attr_init(&attr);
if (ret != 0) {
printf("init pthread attributes fail(%d)!\n", ret);
exit(-1);
}
memset(&hard_evp, 0, sizeof(struct sigevent));
hard_evp.sigev_value.sival_ptr = &hard_timer;
hard_evp.sigev_notify = SIGEV_THREAD;
hard_evp.sigev_notify_function = watchdog_hard_timeout;
hard_evp.sigev_notify_attributes = NULL;//&attr;
memset(&software_evp, 0, sizeof(struct sigevent));
software_evp.sigev_value.sival_ptr = &software_timer;
software_evp.sigev_notify = SIGEV_THREAD;
software_evp.sigev_notify_function = watchdog_software_timeout;
software_evp.sigev_notify_attributes = NULL;//&attr;
ret = timer_create(CLOCK_REALTIME, &hard_evp, &hard_timer);
if(ret != 0) {
perror("hard timer_create fail!");
exit(-1);
}
ret = timer_create(CLOCK_REALTIME, &software_evp, &software_timer);
if (ret != 0) {
timer_delete(hard_timer);
perror("software timer_create fail!");
exit(-1);
}
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = 0;
ts.it_value.tv_sec = 6;
ts.it_value.tv_nsec = 0;
ret = timer_settime(hard_timer, CLOCK_REALTIME, &ts, NULL);
if(ret != 0) {
perror("hard timer_settime fail!");
timer_delete(hard_timer);
timer_delete(software_timer);
exit(-1);
}
ts.it_value.tv_sec = 10;
ret = timer_settime(software_timer, CLOCK_REALTIME, &ts, NULL);
if(ret != 0) {
perror("hard timer_settime fail!");
timer_delete(hard_timer);
timer_delete(software_timer);
exit(-1);
}
while(1) {
printf("main ready sleep!\n");
sleep(15);
printf("main sleep finish!\n");
}
return 0;
}
#endif