钢筋混凝土的UNIXC编程技巧_第1页
钢筋混凝土的UNIXC编程技巧_第2页
钢筋混凝土的UNIXC编程技巧_第3页
已阅读5页,还剩30页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、钢筋混凝土的 UNIX C 编程技巧(一、内存映射表)前言:大学毕业后从事 unix 上的银行综合业务系统开发工作已有一年半的时间,向众多前辈高手 学习了很多经验和技巧,自己也创新了些好的开发技术,特写出来与奋斗在一线的 unix 程 序员们共享。本人大学时专注于 windows 平台应用开发,工作后才转入 unix 平台,故沿 袭了不少 windows 编码风格。正文:在一个带有数据库的 unix 系统中进行 E-SQL 嵌入式开发, 必然用到很多混合式编程方式。 当系统对表的 SELECT 操作频繁时,会使数据库效率大幅下降。于是我们很当然的这样设 计:当应用开始运行时把数据库中需要频繁查

2、询的表装载入共享内存, 通过编写一批共享内 存查询函数实现对表数据的快速查询、 定位。 这里借用 windows 的一些名词把这一技术命 名为 “内存映射表 ”技术。内存映射表的格式设计有很多方式, 下面介绍一下我设计的一种格式, 该格式已经应用于某 省级银行信用卡全省大前置系统,取得非常好的效果。| | | | | 内存映射表记录条数 | 第一条记录结构单元 | 第二条记录结构单元 | . | 10 个字节| 记录结构的大小| 记录结构的大小共享内存数据存放格式如上图所示。 开头的 10 个字节存放内存映射表的记录条数数值, 由 于标准 c 的有符号长整数类型最大值约为 21 亿,所以预留

3、10 个字节存放 ASCII 编码的记 录条数数值已绰绰有余且取得最大限度值了。 第 11 个字节开始存放数据库表第一条记录对 应的 c 语言结构体,称为一个结构单元。后面依次存放所有数据库表记录形成结构体数组。一张数据库表装载入一块共享内存,可以通过表名给共享内存的 ipckey 取名。比如 “公共 系统参数表 ”对应的内存映射表的 ipckey 在头文件里这样添加 "#define SHMY_KEY_GGXTCS 0x00001138 /* 4408 */",以便于在程序里引用。内存映射表共占用共享内存大小为该表记录对应的数据结构体大小乘以记录条数加上 10 个 字节。

4、比如 “公共系统参数表 ”记录条数为 10 条,表定义如下。那么总占用共享内存大小 =(20+30+40)*10+10=910 个字节。字段名字段属性长度空值标志备注 包括中文注释和取值范围csxhchar20N.N参数序号cszchar30N.N参数值cssmchar40参数说明索引 1 unique csxh公共系统内存映射表的操作大致有装载和查询两种操作, 其它还可以有简单的更新操作。 考虑到每个 内存映射表的操作大致一样以及以某个关键字段查询、更新操作的相似性,再以 参数表 ”我这样设计内存映射表的操作函数原形:int LoadMapGGXTCS();int FetchMapGGXTC

5、S ( void *pvCondValue ,struct REPLACE_STRUCT_TYPE *pREPLACE_STRUCT_ARG , int (* REPLACE_FUNCNAME_COMPARE_PROC)( void *pvCondValue ,struct REPLACE_STRUCT_TYPE *pREPLACE_STRUCT_ARG);int UpdateMapGGXTCS ( void *pvCondValue ,void *pvUpdateValue ,int (* REPLACE_FUNCNAME_UPDATE_PROC)( void *pvCondValue ,v

6、oid *pvUpdateValue ,struct REPLACE_STRUCT_TYPE *pREPLACE_STRUCT_ARG) );两个函数内所有涉及到具体表名、 结构体名、 回调函数名我都已宏的方式替换掉, 这样做的 好处是可以形成代码模板, 如果以后要添加一张表的映射只要复制代码模板到实现文件的最 后面,把代码模板最前面的宏定义成具体的值。 代码模板最后面把所有用过的宏都反定义掉, 不妨碍后面的程序使用。装载表函数我不用多说了,即把表数据装载入共享内存,不需要参数。查询函数第一个参数为关键字段值,与 REPLACE_FUNCNAME_COMPARE_PROC 回调 函数配合使用。

7、 参数类型为 void* 类型, 这样就可以兼容所有类型的数据甚至是结构体、共用体,额外麻烦的只是把变量传入前强制传换成 void* ,在回调函数里再转换回具体的变量 类型。 第二个参数是结构体宏, 用于函数成功返回时把符合要求的记录结构体返回。 第三个 参数是指向回调函数的指针, 其作用是针对某一关键字段, 分别取出共享内存里的每条记录 进行比较,当条件符合时,回调函数返回0 ,否则返回 1 ,这样可以不改变外层遍历函数的条件下,使用不同判断方式、不同的判断值对内存映射表中所有记录进行遍历。本文最后附件中附有装载、 查询和更新三个内存映射表的代码模板, 由于完全采用参数化宏 替换方式设计,甚

8、至可以不加修改的立即应用到您的系统中去。下面跳跃的介绍一下查询函数极其回调函数的操作原理。 更新函数原理与之相似, 结构稍稍 复杂一些,重点是回调函数。查询函数遍历内存映射表中所有结构记录调用遍历函数最后一个参数即回调函数指针(条件值 ,当前结构记录 );如果回调函数返回 0 ,即条件符合且更新成功复制内存映射表中当前结构记录内容到 pREPLACE_STRUCT_ARG 指针空间里,输出给 用户跳出遍历 ;偏移到内存映射表中下一条结构记录 ;返回回调函数的返回值查询回调函数 ( 条件值 ,内存映射表中当前结构记录 )把便利函数传入的条件值强制转换成 char* 类型 ;与内存映射表中当前结构

9、记录的 csxh 进行比较,如果相等即找到 返回 0;否则返回 1;查询函数的使用示例/* 获取 对帐场次 */iRt = FetchMapGGXTCS( (void *)"dzcc" , &stGgxtcs ,&CompareKeyFromGGXTCSWhereCSXHProc );if( iRt != 0 )printf( " 获取对帐场次 失败 " );else printf( " 当前对帐场次为 %s" , stGgxtcs.csz );运行时数据内容使用该设计通过创建与数据库表映射的共享内存数据提高对数据库静

10、态表 不改变或者只做少量更新的表) 的查询访问速度, 而不需要额外占用数据库宝贵的效率, 尤 其在一个对数据库操作频繁的系统中能很大程度的提高整个系统的运行效率。 本设计也有不 足之处,主要是只能代替数据库简单的 SELECT 操作和 UPDATE 操作,不支持 INSERT 、DELETE操作,不过对于一些静态表的查询使用已经足够了,不是吗A_A附件一、内存映射表 代码模块(以 “公共系统参数表 ”为例)/* 获取 公共系统参数表 内存映射表 相应记录 */#define REPLACE_STRUCT_TYPE ggxtcs#define REPLACE_STRUCT_ARG stGgxtc

11、s#define REPLACE_SHEKEY SHMY_KEY_GGXTCS#define REPLACE_TABLENAME ggxtcs#define REPLACE_TABLEDESC " 公共系统参数表 "#define REPLACE_CURSORNAME curGGXTCS#define REPLACE_DBVAR R_GGXTCS#define REPLACE_DBVARFUNC pubVtoSGgxtcs#define REPLACE_FUNCNAME_FETCH "FetchMapGGXTCS"#define REPLACE_FUNC

12、NAME_LOAD "LoadMapGGXTCS"#define REPLACE_FUNCNAME_COMPARE_PROCCompareKeyFromGGXTCSProc#define REPLACE_FUNCNAME_UPDATE_PROC UpdateValueFromGGXTCSProc int FetchMapGGXTCS ( void *pvCondValue ,struct REPLACE_STRUCT_TYPE *pREPLACE_STRUCT_ARG , int (* REPLACE_FUNCNAME_COMPARE_PROC)( void *pvCond

13、Value ,struct REPLACE_STRUCT_TYPE *pREPLACE_STRUCT_ARG);int iReturnValue;struct REPLACE_STRUCT_TYPE *pmpREPLACE_STRUCT_ARG;char *pmp;char acRecordAmount11;long lRecordAmount;long l;_IPC_ID_T ipcid;/* 判断 内存映射表 是否存在 */iReturnValue = IPCIsShareMemoryExist( REPLACE_SHEKEY );if( iReturnValue = IPC_SHAREM

14、EMORY_RETURN_ISNT_EXIST )/* 若不存在 则创建之 */iReturnValue = LoadMapGGXTCS();if( iReturnValue != 0 )WriteLog( gacLogFilename,"%s | "REPLACE_FUNCNAME_FETCH" | "LOG_LINELEN" |创建 内存映射表"REPLACE_TABLEDESC" 失败 错误码 %d errno%d,请重启应用 n",GetLocalTimeString( gacTimeStringBuffe

15、r , 256 , "%Y-%m-%d %H:%M:%S" ),_LINE_,iReturnValue,errno );return -1;/* 打开 内存映射表 */ipcid = IPCOpenShareMemory( REPLACE_SHEKEY );if( ipcid < 0 )/* 打开失败,写出错日志,函数返回 */WriteLog( gacLogFilename,"%s | "REPLACE_FUNCNAME_FETCH" | "LOG_LINELEN" |打开 内存映射表"REPLACE_TA

16、BLEDESC" 失败 errno%d ,请重启应用 n",GetLocalTimeString( gacTimeStringBuffer , 256 , "%Y-%m-%d %H:%M:%S" ),_LINE_,errno );return -2;/* 连接 内存映射表 地址 */pmp = IPCAttachShareMemory( ipcid );if( pmp = NULL )/* 连接失败,写出错日志,函数返回 */WriteLog( gacLogFilename,"%s | "REPLACE_FUNCNAME_FETCH&

17、quot; | "LOG_LINELEN" |连接 内存映射表"REPLACE_TABLEDESC" 失败 errno%d ,请重启应用 n",GetLocalTimeString( gacTimeStringBuffer , 256 , "%Y-%m-%d %H:%M:%S" ),_LINE_,errno );return -3;memset( acRecordAmount , 0x00 , sizeof( acRecordAmount ) );strncpy( acRecordAmount , pmp , 10 );lR

18、ecordAmount = atol( acRecordAmount );pmpREPLACE_STRUCT_ARG = (struct REPLACE_STRUCT_TYPE *)( pmp + 10 ) ;/* 搜寻 内存映射表 */for( l=0 ; l<lRecordAmount ; l+ )/* 调用搜寻回调函数 */iReturnValue = REPLACE_FUNCNAME_COMPARE_PROC( pvCondValue , pmpREPLACE_STRUCT_ARG ) ;if( iReturnValue != 1 )memset( pREPLACE_STRUCT

19、_ARG , 0x00 , sizeof( struct REPLACE_STRUCT_TYPE ) );memcpy( pREPLACE_STRUCT_ARG , pmpREPLACE_STRUCT_ARG , sizeof(struct REPLACE_STRUCT_TYPE) );break;pmpREPLACE_STRUCT_ARG + ;/* 断开 内存映射表 地址连接 */IPCDetachShareMemory( pmp );return iReturnValue;/* 更新 公共系统参数表 内存映射表 * */ int UpdateMapGGXTCS ( void *pvCon

20、dValue , void *pvUpdateValue , int (* REPLACE_FUNCNAME_UPDATE_PROC)( void *pvCondValue , void *pvUpdateValue ,struct REPLACE_STRUCT_TYPE *pREPLACE_STRUCT_ARG);int iReturnValue;struct REPLACE_STRUCT_TYPE *pmpREPLACE_STRUCT_ARG;char *pmp;char acRecordAmount11;long lRecordAmount;long l;_IPC_ID_T ipcid;

21、/* 判断 内存映射表 是否存在 */iReturnValue = IPCIsShareMemoryExist( REPLACE_SHEKEY );if( iReturnValue = IPC_SHAREMEMORY_RETURN_ISNT_EXIST )/* 若不存在 则创建之 */iReturnValue = LoadMapGGXTCS();if( iReturnValue != 0 )WriteLog( gacLogFilename,"%s | "REPLACE_FUNCNAME_FETCH" | "LOG_LINELEN" |创建 内存

22、映射表"REPLACE_TABLEDESC" 失败 错误码 %d errno%d ,请重启应用 n",GetLocalTimeString( gacTimeStringBuffer , 256 , "%Y-%m-%d %H:%M:%S" ),_LINE_,iReturnValue,errno );return -1; /* 打开 内存映射表 */ ipcid = IPCOpenShareMemory( REPLACE_SHEKEY );if( ipcid < 0 )/* 打开失败,写出错日志,函数返回 */WriteLog( gacLog

23、Filename,"%s | "REPLACE_FUNCNAME_FETCH" | "LOG_LINELEN" |打开 内存映射表"REPLACE_TABLEDESC" 失败 errno%d ,请重启应用 n",GetLocalTimeString( gacTimeStringBuffer , 256 , "%Y-%m-%d %H:%M:%S" ),_LINE_,errno );return -2;/* 连接 内存映射表 地址 */pmp = IPCAttachShareMemory( ipci

24、d );if( pmp = NULL )WriteLog( gacLogFilename,"%s | "REPLACE_FUNCNAME_FETCH" | "LOG_LINELEN" |连接 内存映射表"REPLACE_TABLEDESC" 失败 errno%d ,请重启应用 n",GetLocalTimeString( gacTimeStringBuffer , 256 , "%Y-%m-%d %H:%M:%S" ),_LINE_,errno );return -3;memset( acRec

25、ordAmount , 0x00 , sizeof( acRecordAmount ) );strncpy( acRecordAmount , pmp , 10 );lRecordAmount = atol( acRecordAmount );pmpREPLACE_STRUCT_ARG = (struct REPLACE_STRUCT_TYPE *)( pmp +10 ) ;/* 搜寻 内存映射表 */ for( l=0 ; l<lRecordAmount ; l+ )/* 调用搜寻回调函数 */iReturnValue = REPLACE_FUNCNAME_UPDATE_PROC( p

26、vCondValue , pvUpdateValue , pmpREPLACE_STRUCT_ARG ) ;if( iReturnValue != 1 )break;pmpREPLACE_STRUCT_ARG + ;/* 断开 内存映射表 地址连接 */IPCDetachShareMemory( pmp );return iReturnValue;/*装载 公共系统参数表 内存映射表* int LoadMapGGXTCS()int iReturnValue;struct REPLACE_STRUCT_TYPE REPLACE_STRUCT_ARG;struct REPLACE_STRUCT_T

27、YPE *pmpREPLACE_STRUCT_ARG; char *pmp;_IPC_ID_T ipcid;long lMapSize;memset( &REPLACE_STRUCT_ARG , 0x00 , sizeof( structREPLACE_STRUCT_TYPE ) );/* 获取表记录总条数 */EXEC SQLSELECT count(*)INTO :dlRecordAmountif( sqlca.sqlcode )WriteLog( gacLogFilename,"%s | "REPLACE_FUNCNAME_LOAD" | "

28、;LOG_LINELEN" |获取"REPLACE_TABLEDESC" 总记录数 失败 sqlcode%dn",GetLocalTimeString( gacTimeStringBuffer , 256 , "%Y-%m-%d %H:%M:%S" ),_LINE_,sqlca.sqlcode );return -1;/* 计算内存映射表大小 */* 前十个字节为储存头,存放储存单元的个数 */lMapSize = dlRecordAmount * sizeof( structREPLACE_STRUCT_TYPE ) + 10 ;/

29、* 创建 内存映射表 */ipcid = IPCCreateShareMemory( REPLACE_SHEKEY , lMapSize );if( ipcid < 0 )if( errno = EEXIST )return 0;WriteLog( gacLogFilename,"%s | "REPLACE_FUNCNAME_LOAD" | "LOG_LINELEN" | 创建 内存映射表"REPLACE_TABLEDESC" 失败 errno%d ,请重启应用 n",GetLocalTimeString(

30、gacTimeStringBuffer , 256 , "%Y-%m-%d %H:%M:%S" ),_LINE_,errno );return -2;/* 定义游标 */EXEC SQLDECLARE REPLACE_CURSORNAME CURSOR FORSELECT */* 打开游标 */EXEC SQLOPEN REPLACE_CURSORNAME ;/* 打开游标 失败 */if( sqlca.sqlcode )WriteLog( gacLogFilename,"%s | "REPLACE_FUNCNAME_LOAD" | "

31、;LOG_LINELEN" | 打开 游标"REPLACE_TABLEDESC" 失败 sqlcode%dn",GetLocalTimeString( gacTimeStringBuffer , 256 , "%Y-%m-%d %H:%M:%S" ),_LINE_, sqlca.sqlcode );return -3;/* 连接 内存映射表 地址 */ pmp = IPCAttachShareMemory( ipcid );if( pmp = NULL )/* 连接失败,写出错日志,函数返回 */WriteLog( gacLogFil

32、ename,"%s | "REPLACE_FUNCNAME_LOAD" | "LOG_LINELEN" |连接 内存映射表"REPLACE_TABLEDESC" 失败 errno%d ,请重启应用 n",GetLocalTimeString( gacTimeStringBuffer , 256 , "%Y-%m-%d %H:%M:%S" ),_LINE_,errno );return -4;sprintf( pmp , "%-010d" , dlRecordAmount );

33、pmpREPLACE_STRUCT_ARG = (struct REPLACE_STRUCT_TYPE *)( pmp +10 ) ;while(1)/* 获取游标 */EXEC SQLFETCH REPLACE_CURSORNAMEINTO REPLACE_DBVAR;/* 如果记录已取完,跳出循环 */if( sqlca.sqlcode = 100 )break;/* 获取游标 失败 */if( sqlca.sqlcode != 0 )WriteLog( gacLogFilename,"%s | "REPLACE_FUNCNAME_LOAD" | "

34、LOG_LINELEN" |获取游标"REPLACE_TABLEDESC" 失败 sqlcode%d ,请重启应用 n",GetLocalTimeString( gacTimeStringBuffer , 256 , "%Y-%m-%d %H:%M:%S" ),_LINE_, sqlca.sqlcode );/* 断开 内存映射表 地址连接 */IPCDetachShareMemory( pmp );/* 关闭游标 */EXEC SQL CLOSE REPLACE_CURSORNAME;return -5;REPLACE_DBVARF

35、UNC( &REPLACE_STRUCT_ARG );memcpy( pmpREPLACE_STRUCT_ARG , &REPLACE_STRUCT_ARG , sizeof( struct REPLACE_STRUCT_TYPE ) );pmpREPLACE_STRUCT_ARG + ;/* 断开 内存映射表 地址连接 */IPCDetachShareMemory( pmp );/* 关闭游标 */EXEC SQL CLOSE REPLACE_CURSORNAME;WriteLog( gacLogFilename,"%s | "REPLACE_FUNCNA

36、ME_LOAD" | "LOG_LINELEN" | %ld条记录进入 内存映射表 "REPLACE_TABLEDESC" n",GetLocalTimeString( gacTimeStringBuffer , 256 , "%Y-%m-%d %H:%M:%S" ), _LINE_, dlRecordAmount );return 0;#undef REPLACE_STRUCT_TYPE#undef REPLACE_STRUCT_ARG#undef REPLACE_SHEKEY#undef REPLACE_TAB

37、LENAME#undef REPLACE_TABLEDESC#undef REPLACE_CURSORNAME#undef REPLACE_DBVAR#undef REPLACE_DBVARFUNC#undef REPLACE_FUNCNAME_FETCH#undef REPLACE_FUNCNAME_LOAD#undef REPLACE_FUNCNAME_COMPARE_PROC#undef REPLACE_FUNCNAME_UPDATE_PROC附件二、 下面这些函数被上面的程序调用过,代码存放在本人设计的iIPC 、iLibX 基础函数库中。/* 函数名 : IPCIsShareMemo

38、ryExist* 函数描述 : 判断共享存储块存在* 输入参数说明 : _IPC_ID_T ipckey 共享存储块的 id* 返回值 : 存在 返回 IPC_SHAREMEMORY_RETURN_EXIST* 不存在 返回 IPC_SHAREMEMORY_RETURN_ISNT_EXIST*/int IPCIsShareMemoryExist( _IPC_KEY_T ipckey )_IPC_ID_T ipcid;ipcid=shmget( ipckey , 1 , IPC_CREAT | IPC_EXCL | _giIPCPermission );if( ipcid = -1 ) retu

39、rn IPC_SHAREMEMORY_RETURN_EXIST;IPCDestroyShareMemory( ipcid );return IPC_SHAREMEMORY_RETURN_ISNT_EXIST;/* 函数名 : IPCOpenShareMemory* 函数描述 : 打开共享存储块key* 输入参数说明 : _IPC_KEY_T ipckey共享存储块的* 返回值 : 成功,返回 共享存储块的 id* 失败,返回 错误代码*/_IPC_ID_T IPCOpenShareMemory( _IPC_KEY_T ipckey )int iReturnValue;IPC_ID_T ipci

40、d; iReturnValue = IPCIsShareMemoryExist( ipckey ) ;if( iReturnValue = IPC_SHAREMEMORY_RETURN_ISNT_EXIST ) return IPC_SHAREMEMORY_RETURN_ISNT_EXIST;ipcid = shmget( ipckey , 0 , IPC_CREAT | _giIPCPermission );if( ipcid = -1 )return IPC_SHAREMEMORY_ERROR_CANT_OPEN;return ipcid;/* 函数名 : IPCAttachShareMe

41、mory* 函数描述 : 连接共享存储块首地址* 输入参数说明 : _IPC_ID_T ipcid 共享存储块的 id* 返回值 : 存在 返回 首地址* 不存在 返回 NULL*/ void *IPCAttachShareMemory( _IPC_ID_T ipcid ) void *pvAttach;pvAttach = shmat( ipcid , NULL , 0 );if( pvAttach = (void *)-1 )return NULL;elsereturn pvAttach;/* 函数名 : IPCDetachShareMemory* 函数描述 : 断开共享存储块首地址* 输

42、入参数说明 : void *pvDetach共享存储块连接首地址* 返回值 : 存在 返回 IPC_SHAREMEMORY_RETURN_SUCCESS* 不存在 返回 IPC_SHAREMEMORY_ERROR_CANT_DETACH*/ int IPCDetachShareMemory( void *pvDetach ) int i;i = shmdt( pvDetach );if( i = -1 )return IPC_SHAREMEMORY_ERROR_CANT_DETACH;elsereturn IPC_SHAREMEMORY_RETURN_SUCCESS;/* 函数名 : Writ

43、eLog* 函数描述 : 正常写日志函数* 输入参数说明 : char *pcLogFileName 日志文件名* char *pcFormatString 日志格式串* . 日志参数列表* 返回值 : 成功,返回 TRUE* 失败,返回 FALSE*/BOOL WriteLog( char *pcLogFileName, char *pcFormatString, . )va_list valist;BOOL ret;va_start( valist, pcFormatString );ret=DoLog(pcLogFileName, LOG_WRITE_APPEND, LOG_MODE_RETURN,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论