分享
 
 
 

转一个很好的Oracle贴子

王朝oracle·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

用Pro*C开发多线程应用程序

(注:本文来自Pro*C/C++ Precompiler Programmer's Guide Release 8.1.5)

假如你的操作系统不支持线程,本文暂不适合你。本文包含以下几个部分:

n 什么是多线程?

n Pro*C中的运行时上下文

n 运行时上下文的使用模式

n 多线程应用程序的用户接口

n 多线程例子

一.什么是多线程?

一个多线程的应用程序中,线程运行在共享的地址空间里。线程是在进程内部执行的“轻量”级子进程,它们共享代码段和数据段,但是有自己的程序计数器、寄存器和堆栈。全局变量和静态变量在线程之间是共享的,因此通常需要在程序中使用某种互斥机制来治理线程对这些变量的访问,互斥体Mutexes就是用来保证数据完整性的同步装置。

有关互斥体的更多讨论,参看多线程编程方面的文章。

Proc*C编译器通过以下方式支持开发多线程的Oracle应用程序(在支持线程的平台上):

n 用一个命令行编译选项来产生线程安全的代码

n 用内嵌的SQL语句和指令支持多线程

n 线程安全的Lib库和其他客户端Lib库

注重:也许你的平台支持某个非凡的线程包,但还是需要查看Oracle有关平台的文档,看看Oracle是否支持它。

二.Pro*C中的运行时上下文

为了在线程和数据库连接之间建立松散的结合,Pro*C引入了一个概念runtime_context,我们称之为运行时上下文。一个运行时上下文包含了以下资源和信息:

n 与数据库服务器的连接

n 当前连接上使用的游标

n 内嵌的一些选项,如MODE,HOLD_CURSOR,RELEASE_CURSOR和 SELECT_ERROR

不仅仅是简单的支持线程和连接之间的松散结合,Pro*C编译器还答应开发人员在线程和运行时上下文之间建立松散的结合,Pro*C答应在程序里为运行时上下文定义一个句柄,通过这个句柄,运行时上下文可以在线程之间切换。

例如,一个交互式应用程序创建了线程T1,来执行一个查询,并且返回了前10条记录,然后T1终止。在用户输入了必须的数据之后,程序又创建了线程T2,并且把T1使用的运行时上下文传给T2,这样T2可以在同一个游标上获取接下来10条的记录。

三.运行时上下文的使用模式

下面是在多线程的Pro*C程序中使用运行时上下文的两种可能模式:

n 多线程共享单个运行时上下文

n 多线程使用互相独立的运行时上下文

不管采用哪种模式,不能在同一时刻多个线程共享同一个运行时上下文。假如两个或两个以上的线程在同一时刻试图使用同一个运行时上下文,将会出现以下错误:SQL-02131: Runtime context in use。

1.多线程共享单个运行时上下文

图(一)展示了一个运行在多线程环境中的应用程序,多个线程共享一个运行时上下文来执行SQL语句,运行时上下文不能在同一时刻被多个线程使用,图中的Mutex展示了如何防止这种并行使用。

图(一)

2.多线程使用互相独立的运行时上下文

图(二)展示了使用多个运行时上下文的多线程应用程序,在这种情况下,程序不需要使用互斥锁Mutex,因为每个线程拥有一个独立的运行时上下文。

图(二)

四.多线程应用程序的用户接口

Pro*C编译器提供以下接口来支持多线程:

n 命令行选项,THREADS=YESNO

n 内嵌SQL语句和指令

n 线程安全的公共库函数

1.THREADS选项

在proc预编译命令行上指定THREADS=YES,Pro*C编译器将保证产生的C代码是线程安全的。假如指定了THREADS=YES,Pro*C将会检查每个包含SQL执行语句的函数,是否指定了这些语句是在哪个运行时上下文中执行的,若没有发现这类指定标识,编译器就会返回错误。

2.内嵌SQL语句和指令

下列内嵌的SQL语句和指令用于支持多线程和运行时上下文的使用:

n EXEC SQL ENABLE THREADS;

n EXEC SQL CONTEXT ALLOCATE :context_var;

n EXEC SQL CONTEXT USE {:context_var/DEFAULT};

n EXEC SQL CONTEXT FREE :context_var;

在以上SQL语句中,context_var是运行时上下文句柄,它必须被定义成sql_context类型:如sql_context context_var;

使用DEFAULT意味着接下来的SQL语句将使用默认的全局运行时上下文,直到另一条CONTEXT USE语句覆盖它。

n EXEC SQL ENABLE THREADS

这条可执行SQL语句初始化支持多线程的进程。它必须是程序中第一条可执行的SQL语句。

n EXEC SQL CONTEXT ALLOCATE

这条可执行SQL语句分配并初始化了一块用于指向一个新的运行时上下文的内存,并返回标识该上下文的句柄变量,该变量必须声明为sql_context类型。

n EXEC SQL CONTEXT USE

这条指令性语句告诉编译器接下去执行的SQL语句将使用指定的运行时上下文,这里的运行时上下文必须在此前已经用CONTEXT ALLOCATE分配并初始化。

n EXEC SQL CONTEXT FREE

这条语句释放了运行时上下文句柄指定的内存,并把它设置空值。

3.编程时要考虑的问题

尽管Oracle保证SQL库是线程安全的,但是你还是有责任保证你的Pro*C代码是为能在多线程下正确运行而设计的,例如,你必须考虑全局变量和静态变量的。

另外,多线程要求对以下问题进行考虑:

n 把sqlca结构定义成线程安全的。典型的做法是在每个函数开始定义一个同名的局部变量。

n sqlda结构也和sqlca结构一样处理。

n 把程序里的宿主变量定义成线程安全的。也就是说要小心处理程序里的全局变量和静态变量。

n 避免同一时刻不同线程使用同一个运行时上下文。

五.多线程例子

下面的例子运行在Red Hat9和Oracle9上。程序目的是用两个线程同时往一个表里插10000条记录,每个线程都拥有自己的运行时上下文。

#include<stdio.h>

#include<unistd.h>

#include<pthread.h> /* Linux线程库头文件 */

#include "sqlca.h" /* Oracle头文件 */

#define SQLCODE sqlca.sqlcode

static int insert_data( sql_context );

static int start();

int

main()

{

pthread_t tid1, tid2;

/* 创建两个线程 */

if( pthread_create( &tid1,NULL,(void *)start,NULL ) ){

printf( "创建线程失败!\n" );

exit(1);

}

if( pthread_create( &tid2,NULL,(void *)start,NULL ) ){

printf( "创建线程失败!\n" );

exit(1);

}

/* 等待线程退出 */

if( pthread_join( tid1,NULL ) ){

printf( "等待线程结束失败!\n" );

exit(1);

}

if( pthread_join( tid2,NULL ) ){

printf( "等待线程结束失败!\n" );

exit(1);

}

exit(0);

}

int

start()

{

sql_context context;

strUCt sqlca sqlca; /* 需要在此定义一个局部的sqlca */

char uid[] = "dev/888888";

/* 以下SQL语句的执行顺序不能更改 */

EXEC SQL ENABLE THREADS;

EXEC SQL CONTEXT ALLOCATE :context;

EXEC SQL CONTEXT USE :context;

EXEC SQL CONNECT :uid;

if( SQLCODE < 0 ){

printf( "创建数据库连接失败,%d:%s\n", SQLCODE,sqlca.sqlerrm.sqlerrmc);

return -1;

}insert_data( context );

EXEC SQL COMMIT WORK RELEASE;

if( SQLCODE < 0 ){

printf( "断开数据库连接失败!%d:%s\n", SQLCODE,sqlca.sqlerrm.sqlerrmc );

return -1;

}

EXEC SQL CONTEXT FREE :context;

return 0;

}

static int

insert_data( context )

sql_context context;

{

struct sqlca sqlca; /* 需要在此定义一个局部的sqlca */

char name[11];

int age;

int i;

strcpy( name, "test" );

age = 20;

EXEC SQL CONTEXT USE :context; /* 指定执行SQL语句的上下文 */

for( i=0; i<10000; i++ ){

EXEC SQL INSERT INTO table1 VALUES ( :name, :age );

if( SQLCODE < 0 ){

printf( "插入纪录失败!%d:%s\n", SQLCODE, sqlca.sqlerrm.sqlerrmc );

return -1;

}

}

return 0;

}

本论坛有

http://bbs.chinaunix.net/forum/47/20031216/223940.Html

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有