2009-08-03 21 views
3

我們有一個處理事件定時器的API。這個API說它使用OS回調來處理定時事件(顯然使用select())。Unix中的C++定時器

的API權利要求執行的該順序,以及: 可讀事件 可寫事件 計時器事件

這通過創建指向一個定時器對象,但傳遞創建功能的功能回調:

沿着這些線:

Timer* theTimer = Timer::Event::create(timeInterval,&Thisclass::FunctionName); 

我想知道這是如何工作的?
操作系統正在處理定時器本身,並且當它看到它被觸發時它如何實際調用回調?回調是否在單獨的執行線程中運行?

當我在回調函數(Thisclass :: FunctionName)中放置一個pthread_self()調用時,它看起來與自己創建Timer的線程具有相同的線程ID! (由此非常困惑)

另外:以上的優先級列表是什麼意思?什麼是可寫事件vs可讀事件vs計時器事件?

也讚賞在這種情況下使用select()的任何解釋。

謝謝!

+2

鏈接到相關API的文檔會很有幫助等待所有計時器。如果它是一些內部的東西,請閱讀源代碼;有許多方法可以實施。 – bdonlan 2009-08-03 15:45:17

回答

2

這看起來像一個簡單的包裝select(2)。這個類保存了一個回調列表,我猜是分開讀取,寫入和計時器到期的。然後有一個像調用dispatchwaitwait的調用,將給定的文件描述符打包成集合,計算最小超時值,並用這些參數調用select。當select返回時,包裝器可能會先讀取set,調用read回調,然後寫入set,然後查看是否有任何定時器已過期並調用這些回調。這一切都可能發生在同一個線程上,或者在單獨的線程上發生,具體取決於包裝器的實現。

您應該閱讀selectpoll - 它們非常方便。 通用術語是IO解複用

1

根據猜測,對create()的調用將函數指針存儲在某處。然後,當計時器關閉時,它會調用您通過該指針指定的函數。但是,由於這不是標準C++函數,所以您應該真正閱讀文檔或查看源代碼以確定。

關於您的其他問題,我沒有看到提及優先級列表,select()是一種通用事件多路複用器。

2

可讀事件意味着數據可用於在不阻塞的情況下讀取特定文件描述符,而可寫事件意味着您可以在不阻塞的情況下寫入特定文件描述符。這些通常用於插座和管道。有關這些的詳細信息,請參閱select()手冊頁。

計時器事件意味着先前創建的計時器已過期。如果庫使用的是select()poll(),庫本身必須跟蹤定時器,因爲這些函數接受單個超時。庫必須計算直到第一個定時器到期的剩餘時間,並將其用於超時參數。另一種方法是使用timer_create()或更早的變體(如setitimer()alarm())通過信號接收通知。

您可以使用類似strace(Linux)或truss(Solaris)的工具來確定在OS層使用哪種機制。這些工具跟蹤程序正在進行的實際系統調用。

1

很可能有一個框架與典型的主循環一起工作,主循環的驅動力是select調用。

select允許您等待filedescriptor變爲可讀或可寫(或filedeescriptor上的「異常」)或發生超時。我猜這個庫也允許你爲異步IO註冊回調,如果它是一個GUI庫,它將通過unix上的一個文件描述符得到低級的基本GUI事件。

要在這樣的循環中實現定時器回調,您只需保留定時器的優先級隊列並在選擇超時或filedescriptor事件上處理它們。

優先級意味着它在計時器之前處理文件I/O,這本身需要時間,可能導致GUI更新,最終導致GUI事件處理程序正在運行,或者其他任務花費時間服務I/O。

圖書館或多或少做

for(;;) { 
    timeout = calculate_min_timeout(); 
    ret = select(...,timeout); //wait for a timeout event or filedescriptor events 
    if(ret > 0) { 
    process_readable_descriptors(); 
    process_writable_descriptors(); 
    } 
    process_timer_queue(); //scan through a timer priority queue and invoke callbacks 
} 
0

因爲事實計時器回調內部線程ID是一樣的創造者線程我認爲這是使用信號來實現莫名其妙。

當一個信號發送到線程的狀態被保存並且調用信號處理程序然後調用事件回調。 所以處理程序在創建者線程中被調用,該線程被中斷,直到信號處理程序返回。

也許另一個線程使用select(),如果計時器到期就發出信號至到期定時器在創建線程。