文/顧鵬程
OCI是Oracle公司提供的Oracle數(shù)據(jù)庫的C接口。一些監(jiān)控系統(tǒng),如軌道交通監(jiān)控系統(tǒng)、電力調(diào)度系統(tǒng)等,需要在Linux平臺對OCI進(jìn)行封裝。這類系統(tǒng)實(shí)時性要求較高,而OCI接口在Linux平臺存在斷網(wǎng)阻塞問題,這大大影響了系統(tǒng)實(shí)時性。本文提出一種對已封裝Linux平臺OCI接口的改進(jìn)方法,可在接口斷網(wǎng)阻塞時快速切換至備網(wǎng)。
長期不間斷運(yùn)行的系統(tǒng)不可避免會出現(xiàn)數(shù)據(jù)庫服務(wù)器網(wǎng)線插拔或松動等問題,如果故障未及時恢復(fù),OCI函數(shù)將長時間阻塞,例如在Ubuntu系統(tǒng)可能長達(dá)二十多分鐘,這在大多數(shù)情況下是不允許的。監(jiān)控系統(tǒng)一般配備主備網(wǎng)絡(luò),因此開發(fā)者往往希望當(dāng)發(fā)生阻塞時,數(shù)據(jù)庫接口能夠自動切換網(wǎng)絡(luò)。
在Linux系統(tǒng)中對于阻塞的解決通常使用sigalarm信號,指定信號觸發(fā)時間,在可能的阻塞模塊前調(diào)用alarm函數(shù)。經(jīng)過實(shí)驗(yàn),該方法只是對現(xiàn)有進(jìn)程的打斷,無法對接口函數(shù)給出錯誤返回值,且需退出進(jìn)程,無法保證事務(wù)連貫。
還有采用線程和條件變量相結(jié)合的處理方法,將接口函數(shù)置于線程中執(zhí)行,用條件變量計時等待接口函數(shù)返回。該方法不必退出程序,但未考慮主備網(wǎng)絡(luò)切換,且條件變量方法存在弊端,即當(dāng)信號先于等待發(fā)出時,信號將不再起作用,導(dǎo)致等待無法返回。

圖1:任務(wù)流程
本文以上方法進(jìn)行總結(jié),提出一種結(jié)合泛型、線程、信號量方法的阻塞式任務(wù)線程方法,避免了上述方法的弊端,能夠在接口阻塞時自動切換網(wǎng)絡(luò)。
首先在創(chuàng)建數(shù)據(jù)庫連接時,創(chuàng)建一個任務(wù)線程,負(fù)責(zé)執(zhí)行接口函數(shù)。接口函數(shù)通過泛型進(jìn)入線程。當(dāng)線程被獲得任務(wù)時,觸發(fā)“任務(wù)”信號以執(zhí)行任務(wù)。當(dāng)任務(wù)結(jié)束時,觸發(fā)“返回”信號,主線程返回結(jié)果。調(diào)用接口函數(shù)的模塊在獲得“返回”信號前將一直阻塞并計時,當(dāng)任務(wù)超時,采取tnsping的方式對網(wǎng)絡(luò)狀況進(jìn)行判斷,若網(wǎng)絡(luò)未斷將繼續(xù)等待;若網(wǎng)絡(luò)斷開,將創(chuàng)建備用線程和備用網(wǎng)絡(luò)數(shù)據(jù)庫連接,而后執(zhí)行阻塞任務(wù),并退出原線程。具體流程如圖1所示。
本文采用VC10實(shí)現(xiàn)。泛型部分參考了任務(wù)隊(duì)列的方法,增加了支持不同返回類型的修改。首先定義模版類class Base,結(jié)構(gòu)體struct task_unit由class Base指針對象構(gòu)造,表示任意函數(shù)任務(wù)。任務(wù)的產(chǎn)生由template
阻塞任務(wù)隊(duì)列部分采用ACE庫實(shí)現(xiàn),也可以選擇Linux的C++標(biāo)準(zhǔn)庫實(shí)現(xiàn)。線程類繼承ACE_Task_Base,信號量采用ACE_Semaphore,“任務(wù)”信號初始化為 t_sem(0),“返回”信號初始化為r_sem(0)。線程通過調(diào)用t_sem.acquire()等待任務(wù)注入。主線程將任務(wù)注入任務(wù)線程后,調(diào)用t_sem.release()觸發(fā)任務(wù)執(zhí)行,調(diào)用r_sem.acquire(&timeout)等待任務(wù)完成,其中timeout為超時設(shè)置。任務(wù)結(jié)束時,線程調(diào)用ret_sem.release(),使主線程獲得返回值。
本文方法對Linux平臺OCI接口的網(wǎng)絡(luò)阻塞問題進(jìn)行處理,針對已封裝的接口函數(shù),只需利用泛型、多線程、信號量,即可構(gòu)造一個通用的阻塞模式任務(wù)隊(duì)列,將接口函數(shù)置于阻塞任務(wù)隊(duì)列下,在網(wǎng)絡(luò)阻塞時,通關(guān)新的線程調(diào)用備用網(wǎng)絡(luò),解決了原本OCI接口函數(shù)長時間阻塞的問題。經(jīng)過實(shí)驗(yàn),該方法對舊有接口的改造工作量小,并且能實(shí)現(xiàn)應(yīng)用的數(shù)據(jù)庫連接在網(wǎng)絡(luò)發(fā)生通斷問題時進(jìn)行自動切換。