我想在一个Service Context中,同时执行多个事务(都是本地事务),请问可以吗?如果可能的话,具体如何做?能给出例子吗?谢谢!

解决方案 »

  1.   

    把这些事物写成过程,Service Context调用
      

  2.   

    我也是copy⑴初始化和结束函数
    在调用其他函数之前必须调用OCIThreadProcessInit()函数,执行OCIThread软件包的初始化工作,然后再调用OCIThreadInit()函数,初始化OCIThread上下文,供其他OCIThread函数使用。调用OCIThreadTerm()函数,结束OCIThread接口层的处理,释放OCIThread上下文内存。
    ⑵线程管理函数
    类型为OCIThreadHandle的线程句柄用于表示线程的内部数据结构。在使用之前,应该用OCIThreadHndInit()来分配和初始化,用完后应调用OCIThreadHndDestroy()来释放内存。用OCIThreadCreate()函数创建新线程。用OCIThreadId类型变量来标识一个线程。使用OCIThreadIdInit()来分配和初始化线程ID,而用OCIThreadIdDestroy()来释放线程ID的结构。用OCIThreadClose()函数关闭线程。OCIThreadJoin()函数允许调用者线程与其他线程连接,当要想连接的线程正在运行时,阻塞调用该函数的线程。直到指定的线程运行结束,这个调用者线程才被唤醒,方能继续执行下去。
    ⑶互斥锁管理函数
    在应用程序中用类型OCIThreadMutex的变量来表示互斥锁。互斥锁在使用之前必须用OCIThreadMutexInit()初始化,用完后要用OCIThreadMutexDestroy()释放内存结构。一个线程可用OCIThreadMutexAcquire()来掌握一把互斥锁,任何时候至多只能有一个线程掌握这把互斥锁,掌握这把互斥锁的线程能够用OCIThreadMutexRelease()来释放它。当一个线程掌握这把互斥锁后,其它线程若想再掌握这把互斥锁,就会被阻塞。直到掌握这把锁的线程释放它,被阻塞的线程之一才能得到它,获得互斥锁的线程才能继续执行下去。
      

  3.   

    下面用一个实例来讲述多线程方式ORACLE应用程序的编写和多线程的运行机制,仍以显示地震三维数据体为例。将从数据库中读数据当作一个线程,数据解压,三维图象处理和显示当作另一个线程,在进程中给出二个数据缓冲区,使这二个线程轮流交叉使用这二个缓冲区。并用二把互斥锁来协调这二个线程对缓冲区的使用。为能清楚而简单地说明线程和互斥锁的使用,这里仅给出程序的主要代码段。
    #include <oci.h>
    struct thrs_data {
        OCIThreadMutex *mutex1;  缓冲区1互斥锁
        int buffer1[10240];      缓冲区1 
        OCIThreadMutex *mutex2;  缓冲区2互斥锁
        int buffer2[10240];      缓冲区2 
        int flag;                数据处理结束标志
        int start_read;          开始读数据标志
        int start_disp;          开始显示数据标志
    };
    OCIEnv     *envhp;    OCI环境句柄
    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;   定义数据
    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));
    创建新的线程,执行线程函数调用: 
      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);
    参数read_fun和disp_fun是二个线程函数,op_data是送给线程函数的变量。
    等待线程执行完成并关闭线程句柄:
      OCIThreadJoin(envhp,errhp,tHnd1);
      OCIThreadClose(envhp,errhp,tHnd1);
      OCIThreadJoin(envhp,errhp,tHnd2);
      OCIThreadClose(envhp,errhp,tHnd2);
    释放互斥锁内存:
      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);
    }
    下面是二个线程函数主要代码段:
    void read_fun(dvoid* arg) {   读数据进缓冲区函数
     struct thrs_data *op_data;
     int n=0;
     op_data=(struct thrs_data *)arg;
     for(int k=0;k<5;k++) { 在实际应用中,此处可为for(;;) ,让退出循环的
    条件由要读的实际数据确定,这里用5次循环,是为
    了能够运行给出的框架程序。
       OCIThreadMutexAcquire(envhp,errhp,op_data->mutex1); 获得互斥锁
       op_data->start_read=1; 告诉显示线程,读线程已使用缓冲区
       printf("read data  into buffer1 ...\n");
    在实际应用中,此处应调用“读数据进缓冲区1”的函数。
       OCIThreadMutexRelease(envhp,errhp,op_data->mutex1); 释放互斥锁
    在实际应用中,此处可为:当所有数据都读完时,使op_data->flag=1;并退出循环体
       OCIThreadMutexAcquire(envhp,errhp,op_data->mutex2);
       printf("read data  into buffer2 ...\n");
    在实际应用中,此处应调用“读数据进缓冲区2”的函数。
       if(n==0) while(op_data->start_disp==0); 循环第一次结束时要等待显示线程启
       n=1;                                    动并使用缓冲区 
       OCIThreadMutexRelease(envhp,errhp,op_data->mutex2);
       if(k==2) {          这里的代码段,是为了能演示框架程序; 
         op_data->flag=2;  在实际应用中,此处可为:
         break;            当所有数据都读完时,使op_data->flag=2;
       }                   并退出循环体
     }
    }void disp_fun(dvoid* arg) {  处理和显示数据函数
     struct thrs_data *op_data;
     op_data=(struct thrs_data *)arg; for(;;) {
       while(op_data->start_read==0); 开始时保证读数据线程先使用缓冲区
       OCIThreadMutexAcquire(envhp,errhp,op_data->mutex1);
       op_data->start_disp=1;  告诉读数据线程,显示线程已开始使用缓冲区
       printf(" display buffer1 ...\n");
    在实际应用中,此处应调用“使用缓冲区1中数据,解压,图象处理和显示”的函数。
       OCIThreadMutexRelease(envhp,errhp,op_data->mutex1);
       if(op_data->flag==1) break;  退出循环体,返回
       OCIThreadMutexAcquire(envhp,errhp,op_data->mutex2);
       printf(" display buffer2 ...\n");
    在实际应用中,此处应调用“使用缓冲区2中数据,解压,图象处理和显示”的函数。
       OCIThreadMutexRelease(envhp,errhp,op_data->mutex2);
       if(op_data->flag==2) break; 退出循环体,返回
     }
    }
       thrs_data结构中的几个变量用于读数据线程和显示线程的开始控制和结束控制。start_read:当二个线程同时启动或显示线程先启动时,保证读数据线程先使用缓冲区,=1表示读数据线程已使用了缓冲区;start_disp:在读数据线程对缓冲区进行第一轮操作时,当它已将2个缓冲区写满,而此时显示线程还没有启动或还没有使用过缓冲区,这时应将读数据线程阻塞住,防止它覆盖掉缓冲区中未显示的数据,=1表示显示线程已启动并已使用了缓冲区。在后续交替读数据和显示数据的过程中,由互斥锁来协调二个线程之间的关系。Flag:用于标识数据的结束,=1表示在缓冲区1上结束,=2表示在缓冲区2上结束。
        在PC机LINUX下,使用ORACLE 8i数据库,框架程序的编译连结命令为:
    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