📄
字号:
一. 线程
1. 催缴主线程: 初始化语音卡,初始化数据库,判定催缴条件,
以及协调其它3个线程的工作。
2. 催缴工作线程: 接受处理语音卡事件, 具体进行催缴工作。
3. 数据库读处理线程: 从催缴表中取数据, 并判定是否可以对此
用户催缴, 再往主缓冲区中写数据。
4. 数据库写处理线程: 每成功催缴一次用户, 即在催缴表中将此
用户的催缴次数加1。
其中1,3线程使用分时方式处理,2, 4线程使用消息接收方式处理。
二. 定制文件结构
1. 多个线程共用的数据结构
a.> 主数据缓冲区, 主缓冲区读写指针
typedef struct main_cjdata{
char hth[HTH_LENGTH+1]; //合同号
char num[NUM_LENGTH+1]; //电话号码
char cuijiao[CJJE_LENGTH+1]; //催缴金额
char cjmonth[CJMONTH_LENGTH+1]; //欠缴月份
int cjcount; //催缴成功次数
}MAIN_CJDATA;
主数据缓冲区大小定为100[MAINDATA_LENGTH],
int readmain; //读指针(0-99)
int writemain; //写指针(0-99)
b.> 辅助数据缓冲区, 辅缓冲区读写指针
typedef struct append_cjdata{
char hth[HTH_LENGTH+1]; //合同号
char num[NUM_LENGTH+1]; //电话号码
char cuijiao[CJJE_LENGTH+1]; //催缴金额
char cjmonth[CJMONTH_LENGTH+1]; //欠缴月份
int cjcount; //催缴成功次数
int append_count; //进辅缓冲区的次数
}APPEND_CJDATA;
辅助数据缓冲区大小定为30[APPENDDATA_LENGTH],
int readappend; //读指针(0-29)
int writeappend; //写指针(0-29)
c.> 重拨次数
int cbcount; //即进辅缓冲区的最大次数
d.> TCB线程通信块
typedef struct TreadCtrlBlock{
unsigned int chdevno; //通道号
CWinThread * pThreadOfDbms; //数据库线程指针
}TCB;
用来在催缴工作线程和数据库写处理线程之间通讯
e.> 语音卡通道数据块
typedef struct ch_info{
long chdev; //通道号(通道指针)
int chdevzt; //通道当前所处的状态
int playflag; //播音标志
int chtime; //max over time
_CAP callp; //parameters for PerfectCall
Tone_T tmplts[MAX_TONES]; //PerfectCall tone definitions
int volPos; //current volume setting for playback
}CH_INFO;
主线程打开通道,取得通道指针并写入语音卡通道数据块。
催缴线程具体处理催缴工作。
f.> long chdev[MAXDEVS]; //催缴通道指针队列
int devcounts; //当前用于催缴的通道数目
催缴通道指针队列长度30,并与语音卡通道一一对应,如果某通道工作于催缴
方式,队列中对应的位置即写入该通道的指针,如果某通道未工作于催缴方式,
队列中的对应位置即写入-1。
二. 主线程使用的数据结构
a.> 信号灯原状态
typedef struct old_signlight{
long chdev; //通道号(通道指针)
int workzt; //原工作方式(催缴,查询或未用)
}OLD_SIGNLIGHT;
大小定义为30[MAXDEVS], 保存所有通道原先的工作方式。在查询信号灯时,
若某通道工作于催缴方式,即比较该通道的原工作方式,如果原先不是
工作于催缴方式,则需对此通道进行催缴初始化处理[Init_cuijiao(long chdev)],
并将通道指针加入催缴通道指针队列。如果原先是工作于催缴方式,则无须处理。
若某通道未工作于催缴方式,也比较该通道的原工作方式,如果原先工作于
催缴方式,则需将该通道的指针从催缴队列中删除。如果原先未工作于催缴方式,
则无须处理。
(这种方式等待的指针队列与通道号一一对应,长度为30,未工作于催缴方式的指针设
为空,工作于催缴方式的则设为该通道的指针)
b.> 催缴参数
typedef struct cj_time{
int start_month; //催缴起始和终止时间段
int end_month;
int start_day;
int end_day;
int start_hour;
int end_hour;
int start_minute;
int end_minute;
}CJ_TIME;
typedef struct cj_arg{
CJ_TIME cjtime[3]; //定制三个催缴时间段
int cjtime_one; //时间段一的启用标志(0不启用,1启用)
int cjtime_two; //时间段二的启用标志(0不启用,1启用)
int cjtime_three; //时间段三的启用标志(0不启用,1启用)
int cb_count; //重拨次数
int max_count; //催缴最大次数
int maxcount_flag; //是否使用催缴最大次数的标志(0不使用,1使用)
}CJ_ARG;
三. 催缴工作线程用到的数据结构
四. 数据库读写线程用到的数据结构
A.dll调用
extern "C" __declspec(dllexport) double SquareRoot(double d);
下面是应用程序对该导出函数的显式链接的例子:
typedef double(SQRTPROC)(double);
HINSTANCE hInstance;
SQRTPROC* pFunction;
VERIFY(hInstance=::LoadLibrary("c:\\winnt\\system32\\mydll.dll"));
VERIFY(pFunction=(SQRTPROC*)::GetProcAddress(hInstance,"SquareRoot"));
double d=(*pFunction)(81.0);//调用该DLL函数
B.生成lib库
对于一些常用到的函数,可以生成一个lib库来调用,方法是生成一个lib的project,
然后编译成一个lib。 只是要注意lib函数对于外部变量的操作必须使用参数传递的方法带入
带出,否则生成的lib无使用价值,编译生成lib之后,以后要用到lib中的函数时,只要将lib
的头文件加入到编制的project的include中,以及将lib加入到project的link中,就可以正
确使用了。(c和cpp的lib均可用同样的方法生成)
C.多个cpp使用相同的变量的方法
在一个头文件中定义好该变量,然后对于该变量再定义一个extern的外部说明,使用的时候
在各cpp中包含这个外部说明即可。
D.link时用到的标准库
version.lib libdtimt.lib libdxxmt.lib sctools.lib libgc.lib libfaxmt.lib libsrlmt.lib
E.ODBC驱动
Microsoft ODBC for Oracle 版本 2.573.3711.00 MSORCL32.dll 01/01/99
此版本的ODBC可支持自动重连,即当网线断开,与服务器失去连接时,此驱动会在
网络恢复连接后自动再连上服务器数据库。(超时60s,重试等待时间120s,这两个参
数ODBC数据源管理器中可设置)
但是对于服务器杀掉连接进程后,这个ODBC不能自动修复连接,仍需编程修复
五. 实时读取数据催缴
催缴的新条件:2001.02.15
催缴表每月生成一次,但是生成后会实时的更新。
催缴时必须能指定催缴的合同号,催缴合同号可能是连续的或是间断的。
2001.02.19
催缴方式进行了一次较大的变动,就是将读数据设定在催缴时间段内进行,而催缴时间段外不读取数据,
因为催缴数据实时更新,若读数据在催缴时间段外进行,则有可能出现原先读到缓冲区内的数据已经更新,但
催缴系统却不知道,而在下一个催缴时间段继续按原有数据拨打催缴电话,出现错误催缴的情况。
将读数据改为在催缴时间段内进行后,系统即时读取数据,即时催缴,不会有较大的时间间隔。当时间到达
催缴时间段外时,系统将停止读数据,而且会将缓冲区内剩余的催缴数据全部拨出,不会留下老数据在缓冲区内。
这样就可以实现催缴数据的实时更新,实时催缴,不会出现用户交费之后,还接到催缴电话的情况。
相对原来的催缴读数据方式,只是催缴速度略有降低,其它没有影响。
六. 催缴数据更新方式
根据计费服务器上是否存在xtcj170.flag 文件来决定是整表传输还是更新传输。
计费服务器10.88.93.2 /data2/xtydj/xtcj170.flag
170服务器`10.88.92.8 /u1/xt170/ftpd/data/xtcj170.flag
2000.2.21
试运行中出现的问题
1. 有两个通道在试运行时阻塞在两个号码的振铃状态,虽然有超时处理机制,
但隔了一天也没有恢复。
一.可能原因
a.(yin_seize)运行到
if((tsbits=ATDT_TSSGBIT(dxinfo[i].dtdev))==AT_FAILURE){
TRACE("ATDT_TSSGBIT() error");
return -1;
}
出错
b. 问题可能是两个通道的信号灯状态没有置为空闲,所以
催缴系统就无法再使用这两个通道。
二.解决方案
a.自动修复:使用系统超时处理机制,每隔10分钟检测一下各通道是否长时间处于工作
状态,若是则关闭该通道然后再重新打开。
b.手工修复:每个通道均在界面上提供一个按纽,此按纽可完成重新打开某一通道的功能。
(a,b方案同时采用)
(已修改,待测试)
2. 有些记录写日志不成功
3. 日志记录不完整,有的日志记录只有合同号
4. 少数催缴标志为9的也被催缴
原因
a.由于所打开的催缴记录集使用了缓冲区,造成了虽然数据库内的记录已经更新,但是催缴记录集
却没有更新,所以系统仍按旧数据进行催缴。
解决方案:
a. 重建一个催缴记录集,使用动态连接读数据(暂选a方案) (已修改,待测试)
b. 每更新一次数据,即重新检索一次。
5. 读异常恢复后,应从旧有位置继续往下读 (已修改,待测试)
2000.2.22
改变了记录日志的方式,即在某通道播完催缴音后,系统挂机同时向记录日志线程发送消息,但此时该
通道的信号灯未置位,催缴数据未清除,所以此通道不会用来催缴下一个号码,而直到日志记录完成后,
此通道的信号灯才置为空闲状态,同时清除催缴数据,再用它来催缴其它号码。
原方式是等日志记录完成后才挂机,这就可能造成通话完成后,用户仍须等待一段时间,系统才
会挂断电话。新方式是通话完成即挂机,使接电话的用户不会有空等的时间,新的日志记录方式更合理。
程序运行到读记录第5211时,就不再往下读了。
可能原因:待查
现象:第5211条数据合同号有误,且无催缴金额
原因:系统遇到合同号或金额为空的记录即忽略,但是忘记将记录指针下移,以至
在被忽略的记录处陷入死循环。
(已解决,待测)
2000.2.23
日志记录不完整,有部分催缴成功的用户并没有写入日志。
原因:odbc往数据库写的时候速度较慢,使得部分数据未来得及写入数据库就已达到超时时间。
解决方案:
a. 将记录日志超时时间定长到60秒。(暂选)
b. 写数据库使用pb,不用odbc。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -