在Linux網(wǎng)絡(luò)編程中如何實現(xiàn)信號處理和定時器功能呢_第1頁
在Linux網(wǎng)絡(luò)編程中如何實現(xiàn)信號處理和定時器功能呢_第2頁
在Linux網(wǎng)絡(luò)編程中如何實現(xiàn)信號處理和定時器功能呢_第3頁
在Linux網(wǎng)絡(luò)編程中如何實現(xiàn)信號處理和定時器功能呢_第4頁
在Linux網(wǎng)絡(luò)編程中如何實現(xiàn)信號處理和定時器功能呢_第5頁
已閱讀5頁,還剩5頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第第頁在Linux網(wǎng)絡(luò)編程中如何實現(xiàn)信號處理和定時器功能呢?

關(guān)于epoll驚群問題,什么是驚群呢?

比如我們在寫代碼過程中,使用兩個線程的epoll監(jiān)聽socket,當(dāng)socket上有事件發(fā)生時,兩個epoll都會被喚醒,導(dǎo)致會操作同一個socket,這就是驚群,那如何解決呢?

(1)使用EPOLLEXCLUSIVE:EPOLLEXCLUSIVE是epoll的擴展選項,它允許一個線程獨占一個epoll實例,從而避免了epoll的驚群問題;

(2)使用EPOLLONESHOT:對于注冊了EPOLLONESHOT事件的文件描述符,(操作系統(tǒng))最多觸發(fā)一個可讀,可寫或者異常事件,且觸發(fā)一次,這樣就能確保一個線程獲取事件并處理,但是需要注意的是對于監(jiān)聽類型(如(ac)cept)不能使用EPOLLONESHOT,否則就不能持續(xù)監(jiān)聽連接,對于處理完了的非監(jiān)聽事件,需要重置EPOLLONESHOT;

第一部分:(信號)

1、發(fā)送信號給進(jìn)程

#include#includeintkill((pi)d_tpid,intsig);

2、信號回調(diào)函數(shù)

#includetypedefvoid(__sighandler_tsignal(intsig,__sighandler_t_handler);intsigaction(intsig,conststructsigaction*act,structsigaction*oact);(1)__sighandler_t信號處理的函數(shù)指針,其中處理參數(shù)為觸發(fā)信號當(dāng)前值,其中有兩個默認(rèn)宏(SIG_DFL:使用信號默認(rèn)處理,SIG_IGN:忽略目標(biāo)信號);

(2)signal注冊信號回調(diào)處理函數(shù),返回值為一個函數(shù)指針,含義是這個信號上一次處理的回調(diào)函數(shù)或者是系統(tǒng)默認(rèn)的處理函數(shù),這里目的是讓用戶可以自己恢復(fù)信號處理方式,比如系統(tǒng)對于一些信號是殺掉進(jìn)程的,這里就應(yīng)該處理完自己的回調(diào)邏輯后再調(diào)用系統(tǒng)默認(rèn)行為;

(3)sigaction函數(shù)的功能是檢查或修改與指定信號相關(guān)聯(lián)的處理動作,使用樣例如下:

#include#include#include#includeintmain(){structsigactionnewact,ol(dac)t;newact.sa_handler=SIG_IGN;//設(shè)置信號忽略,也可以設(shè)置為處理函數(shù)sigemptyset(newact.sa_flags=0;intcount=0;pid_tpid=0;sigaction(SIGINT,//原始的備份到oldact,為后續(xù)的處理恢復(fù)pid=f(or)k();if(pid==0){while(1){printf("childexec...n");sleep(1);}return0;}while(1){if(count++>3){sigaction(SIGINT,//恢復(fù)父進(jìn)程信號處理方式kill(pid,SIGKILL);//父進(jìn)程發(fā)信號給子進(jìn)程}printf("fatherexec...n");sleep(1);}return0;}第二部分:(定時器)

在(Linux)(網(wǎng)絡(luò))(編程)中,定時器的作用主要是管理定時任務(wù),處理過期連接,(檢測)超時隊列等,那我們可以通過哪些方式實現(xiàn)定時器呢?

1、利用系統(tǒng)API

...setsockopt(socke(tf)d,SOL_SOCKET,SO_SND(TI)MEO,setsockopt(socketfd,SOL_SOCKET,SO_RCVTIMEO,intnumber=epoll_w(ai)t(fd,events,MAX_EVENT_NUMBER,timeout);...通過使用socket的參數(shù),設(shè)置連接句柄的發(fā)送和接收數(shù)據(jù)超時時間,可以實現(xiàn)定時處理:

(1)SO_SNDTIMEO發(fā)送數(shù)據(jù)超時時間,根據(jù)timeout設(shè)置;

(2)SO_RCVTIMEO接收數(shù)據(jù)超時時間,根據(jù)timeout設(shè)置;

IO復(fù)用的參數(shù)中都帶了一個timeout參數(shù),可以設(shè)置來達(dá)到定時觸發(fā)分支邏輯,比如epoll_wait;

2、簡單的定時器

(1)啟動一個線程實現(xiàn)定時器,具體實現(xiàn)如下圖:

主線程啟動,開始執(zhí)行任務(wù),這里可以是網(wǎng)絡(luò)收發(fā)或者其他;啟動一個線程,做定時任務(wù)處理使用;主線程需要增加定時任務(wù),可以將任務(wù)封裝為task,添加到任務(wù)隊列中;同時通知定時線程,隊列中有任務(wù)了,這里通知機制可以是信號量或者廣播方式;定時線程取出隊列中任務(wù),判斷當(dāng)前任務(wù)是否過期,如果過期就執(zhí)行,沒有過期就繼續(xù)放入任務(wù)隊列中,同時這里需要讓線程等待隊列中距離下一個周期最短的時間,繼續(xù)取隊列任務(wù);(2)使用epoll_wait設(shè)置timeout,是在網(wǎng)絡(luò)事件觸發(fā)的定時器中最方便的方式,具體邏輯如下:

...start_timer=...//開始執(zhí)行時間while(true){intnumber=epoll_wait(epfd,events,MAX_EVENT_NUMBER,timeout);for(...){...//處理連接任務(wù)...}end_timer=...//epoll_wait返回并處理任務(wù)時間//處理定時任務(wù),判斷當(dāng)前時間是否在一個timeoutif(end_timer-start_timer>timeout){//這里是偽代碼,具體時間判斷可以參考linux結(jié)構(gòu)體...//啟動線程執(zhí)行定時任務(wù)邏輯...}}3、時間輪

時間輪是一種高效定時器,通過類似圓盤的形式定義每個tick,定時轉(zhuǎn)動圓盤,假設(shè)每次tick時間為si,一個時間輪有N個tick,那么執(zhí)行轉(zhuǎn)動一圈時間為N*si;

現(xiàn)在插入一個任務(wù),需要to1時間周期后執(zhí)行,這里就分情況處理:

(1)如果to1N*si,則需要分配到(當(dāng)前時間輪的位置+to1/si)的位置上,等待自然tick到達(dá)執(zhí)行當(dāng)前to1的定時任務(wù);

(2)如果to1>N*si,則需要分配到(當(dāng)前時間輪的位置+(to1%N)/si+N)的位置上,由于to1執(zhí)行時間超過一輪的周期,所以需要等待多輪轉(zhuǎn)動后才能執(zhí)行,那如何處理呢?因此我們將每個輪的tick上掛一個鏈表,這個鏈表的節(jié)點表示到達(dá)這個tick需要執(zhí)行的任務(wù)to1,這里的節(jié)點有可能是大于一個輪轉(zhuǎn)動的事件周期,也可能就是當(dāng)前輪時間周期內(nèi)執(zhí)行,我們只需要當(dāng)事件到達(dá)tick時,取出鏈表遍歷鏈表節(jié)點to1,判斷是否是當(dāng)前事件周期內(nèi)執(zhí)行,如果是摘除鏈表節(jié)點然后執(zhí)行任務(wù),如果不是則重新計算to1需要多久后執(zhí)行,計算方法就和上面的一樣(當(dāng)前時間輪位置+((to1-鏈表最小的周期時間)%N)/si+N),然后將當(dāng)前鏈表節(jié)點重新放回;

事件輪

4、時間堆

堆的數(shù)據(jù)結(jié)構(gòu)應(yīng)該大家都比較熟悉了,堆是一種滿足以下條件的樹:

堆中某個節(jié)點的值總是不大于或不小于其父節(jié)點的值;堆總是一棵完全二叉樹;添加堆節(jié)點的時間復(fù)雜度O(lgn),刪除節(jié)點是O(lgn),獲取節(jié)點是O(1);

時間堆

(1)循環(huán)線程讀取最小時間堆的堆頂元素;

(2)取出最小節(jié)點,判斷當(dāng)前事件是否過期,如果過期則繼續(xù)執(zhí)行,否則不處理;

(3)將最小節(jié)點對應(yīng)的事件丟給執(zhí)行線程執(zhí)行;

這里最小時間堆節(jié)點在代碼實現(xiàn)中可以用一個數(shù)組表示,使用完全二叉樹的排列。

#includevoidheapify(intarr[],intn,inti){if(i>=n)return;intmin_node=i;intlson=i*2+1;int(rs)on=i*2+2;if(lson=0;i--){heapify(arr,n,i);}for(inti=n-1;i>=0;i--){swap(arr[i],arr[0]);heapify(arr,i,0);//

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論