久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

怎樣使用OCI編寫多線程的ORACLE應用軟件

 娛天樂 2014-07-18

劉永寧

      中國石化石油勘探開發(fā)研究南京石油物探研究所

摘要:

   多線程的應用程序可充分利用計算機資源,,能有效提高應用程序運行效率。本文通過實例敘述了使用ORACLE OCI 編寫多線程的應用程序方法多線程應用程序的運行機制,。

關鍵字:

  OCI  線程  互斥  應用程序

   將一個較為復雜應用軟件按功能劃分為若干執(zhí)行不同操作的模塊,,再利用多線程機制使它們同時運行處理機或單處理機系統(tǒng)上,提高軟件的運行效率,。本文討論多線程的實用性,,并通過實例(程反復輪流地交叉操作進程中二個緩沖區(qū),,以提高CPU利用來說明多線程的運作機制怎樣利用Oracle提供的編程接口函數(shù),編寫運行在多線程環(huán)境中的數(shù)據(jù)庫應用軟件,。

  1. 多線程實用性

   線程可以看作是由進程產(chǎn)生的一些可執(zhí)行單位,。它們能夠共享進程中相同代碼數(shù)據(jù)段,但它們有自己的程序計數(shù)器,,寄存器和堆棧,。程序中的全局變量對所有線程來講都是公用的。由于多個線程可能會同時訪問這些公用的數(shù)據(jù)元素,,所以機制來管理對這些公用數(shù)據(jù)的訪問,,保證它們正確性。該機制稱為互斥鎖,,它能保證應用程序中同時訪問共享資源的多發(fā)生矛盾沖突,。

   在多處理機系統(tǒng)中多個線程同時運行在不同的處理機上,顯然可以提高軟件的運行速度,;在單處理機系統(tǒng)中,,可用多個線程分開執(zhí)行慢操作(如人機交互,I/O操作等)和快操作(數(shù)據(jù)計算處理),,也可提高軟件的運行效率,。我們考慮顯示地震勘探三維數(shù)據(jù)體程序。常規(guī)的程序流程是: 
 
 
 
 
 
 
 
 
 
 
 
 
 

         從數(shù)據(jù)庫中讀數(shù)據(jù)    解壓   三維圖象處理   顯示 
 
 

由于地震勘探三維數(shù)據(jù)體的數(shù)據(jù)量較大,,從數(shù)據(jù)庫讀數(shù)據(jù)到顯示出圖象的串行操作要花費一些時間,。當數(shù)據(jù)少時,所花時間相對要少,,人有時還感覺不到,;但當數(shù)據(jù)量很大時,這個過程需要花費很多時間,。分析流程中四個步驟就會發(fā)現(xiàn):讀數(shù)據(jù)和顯示部分主要是外部設備打交道,,讀數(shù)據(jù)還需使用網(wǎng)絡;而解壓和三維圖象處理部分基本上是在主機內(nèi)部運算,。我們知道對外設上數(shù)據(jù)的存計算機運算操作在速度上有很大差異,,當外設與主存儲器之間傳輸數(shù)據(jù)時,CPU有時可能出現(xiàn)空閑,。也就是說,,在讀數(shù)據(jù)和顯示數(shù)據(jù)的過程可能會浪費一些CPU資源,。若采用多線程方式編寫這個程序,,就會提高程序的運行效率。整個過程分二個線程:一個讀數(shù)據(jù)線程專門負責從數(shù)據(jù)庫中取數(shù)據(jù);另一個顯示負責數(shù)據(jù)的解壓,,三維圖象處理和顯示輸出,。在程序中安排二個緩沖區(qū)用于存放數(shù)據(jù),。讀數(shù)據(jù)線程輪流地向這緩沖區(qū)中寫數(shù)據(jù),,同樣,顯示線程也跟著輪流地使用緩沖區(qū)中的數(shù)據(jù),。即,數(shù)據(jù)線程向緩沖區(qū)1寫數(shù)據(jù),,顯示線可處理緩沖區(qū)2中的數(shù)據(jù),;而當讀數(shù)據(jù)線程緩沖區(qū)2中寫數(shù)據(jù)時,顯示線程可處理緩沖區(qū)1中的數(shù)據(jù),。這樣,,就將一個進程的串行操作改為二個線程的并行操作,可以充分利用CPU資源,。由于這二個線程可能會同時訪問相同的緩沖區(qū),,這是不允許的,可用互斥鎖機制來協(xié)調(diào)這二個線程之間的關系,。

  1. OCI,,OCI程安全性和線程函數(shù)包

   OCI(Oracle Call Interface)ORACLE提供的面程序員的C語言編程接口,是開發(fā)ORACLE數(shù)據(jù)庫應用軟件較好的工具,。用它開發(fā)出的應用程序運行效率Pro*C/C++的要高,。程序員利用其中提供的函數(shù),能訪問Oracle數(shù)據(jù)庫服務器,。OCI應用程序的主要任務之一是處理SQL語句或PL/SQL腳本,,在程序執(zhí)行的過程將用戶對數(shù)據(jù)庫服務器的請求送到ORACLE服務器,并接收服務器的響應,。

   Oracle數(shù)據(jù)庫服務器和OCI函數(shù)庫的線程安全特征允許程序開發(fā)人員在多線程環(huán)境中使用OCI,。有了線程安全特征,OCI函數(shù)代碼才具有可重入性,,因此從應用程序的多個線同時發(fā)出OCI調(diào)用才不彼此產(chǎn)生不良影響,。實現(xiàn)多線程安全化,應用程序必須在調(diào)用OCI初始化函數(shù)時定義mode參數(shù)為OCI_THREADED,它告訴OCI接口層,,應用程序運行在安全的多線方式中,。

   OCIOCIThread軟件包提供一些線程化函數(shù),主要三種類型,。實際使用情況后面的編程實例,。

   初始結(jié)束函數(shù)

   在調(diào)用其他函數(shù)之前必須調(diào)用OCIThreadProcessInit()函數(shù),執(zhí)行OCIThread軟件包的初工作,然后再調(diào)用OCIThreadInit()函數(shù),,初始化OCIThread上下文,,供其他OCIThread函數(shù)使用。調(diào)用OCIThreadTerm()函數(shù),,結(jié)束OCIThread接口層的處理,,釋放OCIThread上下文內(nèi)存。

   線程管理函數(shù)

   類型為OCIThreadHandle的線程句柄用于表示程的內(nèi)部數(shù)據(jù)結(jié)構(gòu),。在使用之前,,應該用OCIThreadHndInit()來分配始化,用完后應調(diào)用OCIThreadHndDestroy()來釋放內(nèi)存,。OCIThreadCreate()函數(shù)創(chuàng)建新線,。OCIThreadId類型變量來標識一個線使用OCIThreadIdInit()來分配和初始化線程ID,而用OCIThreadIdDestroy()釋放線程ID的結(jié)構(gòu),。OCIThreadClose()函數(shù)關閉線程,。OCIThreadJoin()函數(shù)允許調(diào)用者線其他線程連接,當要想連接的線正在運行時,,阻塞調(diào)用該函數(shù)的,。直到指定的線程運行結(jié)束,這個調(diào)用者線程才被喚醒,,方能繼續(xù)執(zhí)行下去,。

   互斥鎖管理函數(shù)

   在應用程序中用類型OCIThreadMutex的變量來表示互斥鎖?;コ怄i在使用之前必須OCIThreadMutexInit()初始化,,用完后要用OCIThreadMutexDestroy()釋放內(nèi)存結(jié)構(gòu)。一個程可用OCIThreadMutexAcquire()來掌握一把互斥,,任何時候至多只能有一個線程掌握這把互斥鎖,,掌握這把互斥鎖的線程能夠用OCIThreadMutexRelease()來釋放它。當一個線程掌握這把互斥鎖后,,其它線程若想再掌握這把互斥鎖,,就會被阻塞。直到掌握這把的線程釋放它,,被阻塞的線程之一才能得到它,,獲得互斥鎖的線程才能繼續(xù)執(zhí)行下去

  1. 多線程應用軟件編制

   下面用一個實例來講述多方式ORACLE應用程序的編寫和多線程的運行機制,,仍以顯示地震三維數(shù)據(jù)體為例,。將從數(shù)據(jù)庫中讀數(shù)據(jù)當作一個線程,數(shù)據(jù)解,,三維圖象處理顯示當作另一個線程,,在進程出二數(shù)據(jù)緩沖區(qū),使這二個線程輪流交叉使用這二個緩沖區(qū)。并用二把互斥鎖來協(xié)調(diào)這二個線程對緩沖區(qū)的使用,。為能清楚簡單說明程和互斥鎖的使用,,這里僅給出程序的主要代碼段。

#include <oci.h>

struct thrs_data {

    OCIThreadMutex *mutex1;  緩沖區(qū)1

    int buffer1[10240];      緩沖區(qū)1

    OCIThreadMutex *mutex2;  緩沖區(qū)2互斥鎖

    int buffer2[10240];      緩沖區(qū)2

    int flag;                數(shù)據(jù)處理結(jié)束標志

    int start_read;          開始讀數(shù)據(jù)標志

    int start_disp;          開始顯示數(shù)據(jù)標志

};

OCIEnv     *envhp;    OCI環(huán)境句柄

OCIError   *errhp;    OCI錯誤記錄句柄

void read_fun(dvoid *arg);

void disp_fun(dvoid *arg);

int main(int argc, char* argv[])

{

  OCIThreadId *tId1,*tId2;   線程ID句柄

  OCIThreadHandle *tHnd1,*tHnd2; 線程句柄

  struct thrs_data op_data;   定義數(shù)據(jù)

OCI初始化(線程安全性)和分配句柄:

  OCIEnvCreate((OCIEnv **) &envhp,OCI_THREADED,(dvoid *)0,

   (dvoid* (*)(dvoid*,size_t))0,(dvoid* (*)(dvoid*,dvoid*,size_t))0,

   (void (*)(dvoid *, dvoid *)) 0, (size_t) 0,(dvoid **) 0 );

  OCIHandleAlloc((dvoid *)envhp, (dvoid **)&errhp,

    OCI_HTYPE_ERROR,(size_t)0, (dvoid **)0);

線程軟件包和線程初始化:

  OCIThreadProcessInit();

  OCIThreadInit(envhp,errhp);

初始化線程ID和線程句柄:

  OCIThreadIdInit(envhp,errhp,&tId1);

  OCIThreadHndInit(envhp,errhp,&tHnd1);

  OCIThreadIdInit(envhp,errhp,&tId2);

  OCIThreadHndInit(envhp,errhp,&tHnd2);

分配和初始化互斥鎖:

  OCIThreadMutexInit(envhp,errhp,&(op_data.mutex1));

  OCIThreadMutexInit(envhp,errhp,&(op_data.mutex2));

創(chuàng)建新的線程,,執(zhí)行線程函數(shù)調(diào)用:

  op_data.start_read=0; 

  op_data.start_disp=0;

  OCIThreadCreate(envhp,errhp,read_fun,(dvoid *)&op_data,

           tId1,tHnd1);

  OCIThreadCreate(envhp,errhp,disp_fun,(dvoid *)&op_data,

           tId2,tHnd2);

 參數(shù)read_fun和disp_fun是二個線程函數(shù),,op_data是送給線程函數(shù)的變量。

等待線程執(zhí)行完成并關閉線程句柄:

  OCIThreadJoin(envhp,errhp,tHnd1);

  OCIThreadClose(envhp,errhp,tHnd1);

  OCIThreadJoin(envhp,errhp,tHnd2);

  OCIThreadClose(envhp,errhp,tHnd2);

釋放互斥鎖內(nèi)存:

  OCIThreadMutexDestroy(envhp,errhp,&(op_data.mutex1));

 OCIThreadMutexDestroy(envhp,errhp,&(op_data.mutex2));

釋放線程ID和線程句柄:

 OCIThreadIdDestroy(envhp,errhp,&tId1);

  OCIThreadHndDestroy(envhp,errhp,&tHnd1);

  OCIThreadIdDestroy(envhp,errhp,&tId2);

  OCIThreadHndDestroy(envhp,errhp,&tHnd2);

釋放線程上下文:

OCIThreadTerm(envhp,errhp);

釋放所有分配的句柄,。

  OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR);

  OCIHandleFree((dvoid *)envhp, OCI_HTYPE_ENV);

}

下面是二個線程函數(shù)主要代碼段:

void read_fun(dvoid* arg) {   讀數(shù)據(jù)進緩沖區(qū)函數(shù)

struct thrs_data *op_data;

int n=0;

op_data=(struct thrs_data *)arg;

for(int k=0;k<5;k++) { 在實際應用中,,此處可為for(;;) ,讓退出循環(huán)的

                  條件由要讀的實際數(shù)據(jù)確定,這里用5次循環(huán),,是為

                  了能夠運行給出的框架程序,。

   OCIThreadMutexAcquire(envhp,errhp,op_data->mutex1); 獲得互斥鎖

   op_data->start_read=1; 告訴顯示線程,讀線程已使用緩沖區(qū)

   printf("read data  into buffer1 ...\n");

在實際應用中,,此處應調(diào)用“讀數(shù)據(jù)進緩沖區(qū)1”的函數(shù)。

   OCIThreadMutexRelease(envhp,errhp,op_data->mutex1); 釋放互斥鎖

在實際應用中,,此處可為:當所有數(shù)據(jù)都讀完時,,使op_data->flag=1;并退出循環(huán)體

   OCIThreadMutexAcquire(envhp,errhp,op_data->mutex2);

   printf("read data  into buffer2 ...\n");

在實際應用中,此處應調(diào)用“讀數(shù)據(jù)進緩沖區(qū)2”的函數(shù),。

   if(n==0) while(op_data->start_disp==0); 循環(huán)第一次結(jié)束時要等待顯示線程啟

   n=1;                                    動并使用緩沖區(qū)

   OCIThreadMutexRelease(envhp,errhp,op_data->mutex2);

   if(k==2) {          這里的代碼段,,是為了能演示框架程序;

     op_data->flag=2;  在實際應用中,,此處可為:

     break;            當所有數(shù)據(jù)都讀完時,,使op_data->flag=2;

   }                   并退出循環(huán)體

}

} 

void disp_fun(dvoid* arg) {  處理和顯示數(shù)據(jù)函數(shù)

struct thrs_data *op_data;

op_data=(struct thrs_data *)arg; 

for(;;) {

   while(op_data->start_read==0); 開始時保證讀數(shù)據(jù)線程先使用緩沖區(qū)

   OCIThreadMutexAcquire(envhp,errhp,op_data->mutex1);

   op_data->start_disp=1;  告訴讀數(shù)據(jù)線程,顯示線程已開始使用緩沖區(qū)

   printf(" display buffer1 ...\n");

在實際應用中,,此處應調(diào)用“使用緩沖區(qū)1中數(shù)據(jù),,解壓,圖象處理和顯示”的函數(shù),。

   OCIThreadMutexRelease(envhp,errhp,op_data->mutex1);

   if(op_data->flag==1) break;  退出循環(huán)體,,返回

   OCIThreadMutexAcquire(envhp,errhp,op_data->mutex2);

   printf(" display buffer2 ...\n");

在實際應用中,此處應調(diào)用“使用緩沖區(qū)2中數(shù)據(jù),,解壓,,圖象處理和顯示”的函數(shù)。

   OCIThreadMutexRelease(envhp,errhp,op_data->mutex2);

   if(op_data->flag==2) break; 退出循環(huán)體,,返回

}

}

   thrs_data結(jié)構(gòu)中的幾個變量用于讀數(shù)據(jù)線程和顯示線程的開始控制和結(jié)束控制,。start_read:當二個線程同時啟動或顯示線程先啟動時,保證讀數(shù)據(jù)線程先使用緩沖區(qū),,=1表示讀數(shù)據(jù)線程已使用了緩沖區(qū),;start_disp:在讀數(shù)據(jù)線程對緩沖區(qū)進行第一輪操作時,當它已將2個緩沖區(qū)寫滿,而此時顯示線程還沒有啟動或還沒有使用過緩沖區(qū),,這時應將讀數(shù)據(jù)線程阻塞住,,防止它覆蓋掉緩沖區(qū)中未顯示的數(shù)據(jù),=1表示顯示線程已啟動并已使用了緩沖區(qū),。在后續(xù)交替讀數(shù)據(jù)和顯示數(shù)據(jù)的過程中,,由互斥鎖來協(xié)調(diào)二個線程之間的關系。Flag:用于標識數(shù)據(jù)的結(jié)束,,=1表示在緩沖區(qū)1上結(jié)束,,=2表示在緩沖區(qū)2上結(jié)束。

    在PC機LINUX下,,使用ORACLE 8i數(shù)據(jù)庫,,框架程序的編譯連結(jié)命令為:

gcc -g -o thread thread.cpp \

-I$ORACLE_HOME/rdbms/demo -I/usr/i386-glibc20-linux/include \

-I$ORACLE_HOME/rdbms/public -I$ORACLE_HOME/network/public \

-L$ORACLE_HOME/lib -lclntsh  

參考文獻:

   oracle 技術資料:《Oracle Call Interface Programmer’s Guide

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,,謹防詐騙,。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多