一种模块化程序结构

      编程本软件遇到了前所未有的困难,出现了乱如麻,理还乱的问题,使用结构化、模块化、面向对象化的程序设计思想,也未能凑效,为此寻找简化问题的途径。经努力寻找到了一种方式,感觉很眼熟,越看越像某种系统,在网上找到医学人体神经网络结构,才豁然开朗,明白了大意,纠正了概念问题,少走了不少探索的弯路。人体是集中信息处理,分散反馈控制的网络,大脑同各中枢交换信息,做出需“思维”的决定。中枢完成各自的内容,比如:丘脑负责感觉,小脑负责运动等。人体以同时同步进行信息处理。大脑的运动意识传递给小脑,小脑解释该让哪儿动哪儿不动,信息通过脊柱传递给脊髓,脊髓通过神经末梢向有关“运动肌肉”发出命令,同时感觉神经末梢通过脊髓调节,神经纤维沿脊柱向上反馈到丘脑,丘脑“分析”后传递给大脑,完成运动感觉。脊髓可自身构成一个小系统,利用传入和传出的神经,构成执行与反馈调节系统,称为“反射弧”,“反射弧”是人体最小的运动反馈执行部分。

模块化:就像盖大楼,需要一块块砖一样,是构建程序的基础。面向对象是仿生遗传解决复杂问题的一种方法,主要解决代码复用问题,将两者结合起来没什么特别的,也是常做的事情,在两者基础上,根据人体神经网络系统,构建面向对象的模块化神经网络结构,以集中信息处理,分散反馈控制的理念解决程序繁乱的问题,是一种行之有效的程序结构方式。

网络结构类型:以某种结构完成信息归并及处理。

1.  单网络型:分布式结构,分为3级,高级模块相当于“大脑”部分,中枢模块相当于“小脑、丘脑”等中枢部分,功能模块相当于“反射弧”部分。单网络型仅含一个高级模块。

2.  多网络型:跨网络组合结构,每个网络的高级模块模仿“大脑”的左右“半脑”同时同步(并联)工作。

模块间结构:各模块不存在任何直接关联,完全独立,通过信息传递,完成相互关联,依赖。如果一个模块调用了另一个模块,则被调用的模块成为子模块,和调用模块一起,视为一个模块。功能模块同功能模块间通信称为局部连接或局部通信,功能模块同中枢模块间通信称为中枢通信或中枢连接,中枢模块同高级模块间通信称为高级通信或高级连接。中枢模块管理功能模块信息,高级模块管理中枢模块信息,构成集中的信息管理系统。

通信链路:模块都有通信部分,简称“通信部”,通信部由输入输出端口构成,输出端口为静态引用,实际存在,输入端口为指针式引用,输入端口指向输出端口,构成一个连接。每个输入或输出端口也称为“节点”,输出端口称“输出节点”,输入端口称“输入节点”,输出节点向后传称为“链路”,向前(回)传称“反射”。

功能模块:实现具体功能,比如读写文件等,以类为基础实现。

1.  功能部:私有,实现相关功能的函数集,耗时长的,在自有线程中执行。还可自调节,实现简单的仿“反射弧”功能。

2.  接口部:公有,由收发通信构成,用于传递信息,引发事件后调用或触发函数,实现相关功能。

     2.1  接收:接收中枢模块输出部命令,通过调用或触发功能部函数,实现具体功能。

     2.2  发送:通过发送结构,输出功能结果,送达中枢模块输入接口部。

中枢模块:管理协调所属功能模块。

              1. 功能部:私有,辅助接口部,完成接口部的工作。

              2. 接口部:公有,信息交换,调度,控制。

                  2.1 高级通信:同高级模块连接,构成系统。

                        2.1.1 接收:外界信息及资源。

                        2.1.2 发送:需要外界协助的请求信息。

                  2.2 中枢通信:通过端口,协调各功能模块。

                        2.2.1 接收:接收功能模块信息,协调功能模块完成组合功能。

                        2.2.2 发送:向有关功能模块发出操作命令,触发实现其功能。

高级模块:管理协调所有中枢模块。

             (目前未用到,待验证)

高级模块和中枢模块:

通过一个小的局部项目,简单验证这一套想法,是有意义的,目前正在做一个可以独立方便编辑的压缩视频文件,名字为 Fic (Frame Intra Compression File) 帧内压缩文件,先从AVI文件提取RGB视频,暂不压缩,保存为Fic文件,然后再播放,模块结构图如下:

链路流程如下:

目前已初步实现,中枢模块仅实现了交换机功能,部分定义如下:

//模块列表
#define OpModule 1 //操作模块端口编号
#define FicModule 2 //Fic模块端口编号
#define AviModule 3 //Avi模块端口编号
#define MapModule 4 //Map模块端口编号
#define SodModule 5 //Sod模块端口编号

//FIC模块命令集
#define CMD_FIC_OpenR 1 //打开准备读文件
#define CMD_FIC_OpenW 2 //打开准备写文件
#define CMD_FIC_DeFrame 3 //FIC压缩一帧
#define CMD_FIC_EnFrame 4 //FIC压缩一帧
//AVI模块命令集
#define CMD_AVI_OpenR 5 //打开准备读文件
#define CMD_AVI_OpenW 6 //打开准备写文件
#define CMD_AVI_DeFrame 7 //AVI解压一帧
#define CMD_AVI_EnFrame 8 //AVI压缩一帧
//Map模块命令集
#define CMD_Map_SetParam 9//设置屏幕参数
#define CMD_Map_Updata 10 //更新屏幕

主窗体实现模块连接:

//本地命令连接
AviCentral.pRxPort1 = &TxPort1;//Tx1连接,操作模块(命令)->中枢模块
pRxPort1 = &AviCentral.TxPort1;//Rx1连接,操作模块(监视)<-中枢模块
//Fic模块连接
AviCentral.pRxPort2 = &FicFile.TxPort1;//Tx2连接,Fic模块(发送)->中枢模块
FicFile.pRxPort1 = &AviCentral.TxPort2;//Rx2连接,Fic模块(命令)<-中枢模块
//Avi模块连接
AviCentral.pRxPort3 = &AviFile.TxPort1;//Tx3连接,Avi模块(发送)->中枢模块
AviFile.pRxPort1 = &AviCentral.TxPort3;//Rx3连接,Avi模块(命令)<-中枢模块
//Map模块连接
AviCentral.pRxPort4 = &MapScreen.TxPort1;//Tx4连接,Map模块(发送)->中枢模块
MapScreen.pRxPort1 = &AviCentral.TxPort4;//Rx4连接,Map模块(命令)<-中枢模块

临时通过定时器验证Fic文件,链路流程如下:

已看到画面,RGB位序可能反了,颜色不正常,打开文件播放时再打开文件出错没有考虑,待进一步排除后,继续进行。

颜色不正常问题已解决,因为使用vfw调用,输出一帧数据去掉头长度后,怎么调都不是正常颜色,难道是色差信号?换用其他方式提取视频,以节省时间。

以前用过OpenCv提取视频,需要安装,调用静态库,BCB静态库和VC格式不同,用的是以前转化过的,基础工作完以后,顺利得到RGB图像视频,通过RGB视频帧播放,颜色正常。继续解决问题。

需要释放打开的资源后,才能从新打开,“打开”与“释放”必须成对,否则崩溃。通过bIsOpen标志标识打开过没有,打开前先“释放”一下,同时避免正在播放时,退出播放器,“资源”可能被操作系统清除不干净,那可惨了,所以,在模块类销毁前,“释放”一下,避免悲剧发生。问题集中在“释放”也就是停止播放的功能上,不管是自动停止还是手工按钮停止,都要有“停止”的功能,目前中枢模块仅实现了交换机功能,也就是只能执行串联链路功能,从一个端口进,到任意一个端口出,任意一个端口都可以这样。“停止”方式并联比较好,可以同时到达需要“停止”的模块,串化链路目前是固定的,只能沿一个方向走,要改成“万能”的,事先规划好“路线”。当前操作模块的这一部分功能:

DWORD WINAPI TForm1::OperationThread(LPVOID lpParam)//操作线程
{
   TForm1 *pThread = (TForm1 *) lpParam; DWORD dwResult;
   float fTmp0,fTmp1; DWORD dwFrameInterval,dwFrameRate;

   while(1)
   {
     if(pThread->pRxPort1->bActive)//接收端口1
       {
          switch(pThread->pRxPort1->dwCommand)//命令分派
          {
           case CMD_FIC_OpenR:  if(pThread->pRxPort1->bOK)//打开成功
                                  {
                                     pThread->ST4->Caption = pThread->pRxPort1->dwParam[0];//帧数量
                                     pThread->ST1->Caption = pThread->pRxPort1->dwParam[1];//AVI宽度
                                     pThread->ST2->Caption = pThread->pRxPort1->dwParam[2];//AVI高度
                                     //帧率计算
                                     if(pThread->pRxPort1->dwParam[4] != 0)
                                       {
                                          fTmp0 = (float)pThread->pRxPort1->dwParam[3] / (float)pThread->pRxPort1->dwParam[4];
                                       }
                                     dwFrameRate = (DWORD)fTmp0;
                                     pThread->ST5->Caption = dwFrameRate;//显示帧率
                                     //计算帧间延时
                                     if(fTmp0 != 0.0) fTmp1 = 1000.0 / fTmp0;
                                     dwFrameInterval = (DWORD)fTmp1;
                                     pThread->ST6->Caption = IntToStr(dwFrameInterval) + "ms";//帧间延时
                                     pThread->ST7->Caption = pThread->pRxPort1->dwParam[3];//比率
                                     pThread->ST8->Caption = pThread->pRxPort1->dwParam[4];//刻度

                                     pThread->TxPort1.bActive = true;//启动命令
                                     pThread->TxPort1.dwToModule = MapModule;//到Map模块
                                     pThread->TxPort1.dwCommand = CMD_Map_SetParam;//设置屏幕参数
                                     pThread->TxPort1.dwParam[0] = pThread->pRxPort1->dwParam[1];//AVI宽度
                                     pThread->TxPort1.dwParam[1] = pThread->pRxPort1->dwParam[2];//AVI高度
                                  }
                                  else
                                  {
                                     MessageBox(HWND_DESKTOP, "打开Fic文件读失败", "错误", MB_OK | MB_ICONINFORMATION);
                                  }
                                 break;
           case CMD_FIC_OpenW:   if(pThread->pRxPort1->bOK)//打开写成功
                                   {
                                      if(pThread->pRxPort1->dwParam[0] > 0)//大于一帧判断
                                        {
                                           pThread->TxPort1.bActive = true;//启动命令
                                           pThread->TxPort1.dwCommand = CMD_AVI_DeFrame;//Avi解压命令
                                           pThread->TxPort1.dwToModule = AviModule;//链式,前去解压
                                        }
                                        else
                                        {
                                           MessageBox(HWND_DESKTOP, "无视频帧数据。", "失败", MB_OK | MB_ICONINFORMATION);
                                        }
                                   }
                                   else
                                   {
                                       MessageBox(HWND_DESKTOP, "打开Fic文件写失败", "错误", MB_OK | MB_ICONINFORMATION);
                                   }
                                 break;
           case CMD_FIC_DeFrame:  if(pThread->pRxPort1->bOK)//已解压
                                    {
                                       pThread->ProgressBar1->Position = pThread->pRxPort1->dwParam[0];//显示进度
                                       pThread->ST10->Caption = pThread->pRxPort1->dwParam[0];//显示帧号

                                       pThread->TxPort1.bActive = true;//启动命令
                                       pThread->TxPort1.dwToModule = MapModule;//到Map模块
                                       pThread->TxPort1.dwCommand = CMD_Map_Updata;//显示视频数据命令
                                       pThread->TxPort1.pPtr = pThread->pRxPort1->pPtr;//传递指针
                                    }
                                    else
                                    {
                                       pThread->ProgressBar1->Position = 0;//显示进度
                                       pThread->ST100->Caption = " 播放Fic文件已完成。";
                                    }
                                  break;//显示播放帧属性

           //-----------------------------------------------------------------------------------------------------

           case CMD_AVI_OpenR:  if(pThread->pRxPort1->bOK)//打开读Avi文件成功
                                  {
                                     pThread->ST4->Caption = pThread->pRxPort1->dwParam[0];//帧数量
                                     pThread->ST1->Caption = pThread->pRxPort1->dwParam[1];//AVI宽度
                                     pThread->ST2->Caption = pThread->pRxPort1->dwParam[2];//AVI高度
                                     pThread->ST5->Caption = FormatFloat("0.000", pThread->pRxPort1->fParam[0]);//显示帧率

                                     pThread->TxPort1.bActive = true;//启动命令
                                     pThread->TxPort1.dwToModule = MapModule;//到Map模块
                                     pThread->TxPort1.dwCommand = CMD_Map_SetParam;//设置屏幕参数
                                     pThread->TxPort1.dwParam[0] = pThread->pRxPort1->dwParam[1];//AVI宽度
                                     pThread->TxPort1.dwParam[1] = pThread->pRxPort1->dwParam[2];//AVI高度
                                     pThread->TxPort1.dwParam[2] = pThread->pRxPort1->dwParam[3];//帧字节长度
                                  }
                                  else
                                  {
                                     MessageBox(HWND_DESKTOP, "打开Avi文件失败", "错误", MB_OK | MB_ICONINFORMATION);
                                  }
                                 break;

           case CMD_AVI_DeFrame:   pThread->ProgressBar1->Position = pThread->pRxPort1->dwParam[0];//显示进度
                                   pThread->ST10->Caption = pThread->pRxPort1->dwParam[0];//显示帧号
                                   if(pThread->pRxPort1->bOK)//已解压
                                     {
                                        //pThread->TxPort1.bActive = true;//启动命令
                                        //pThread->TxPort1.dwCommand = CMD_FIC_EnFrame;//Fic压缩命令
                                        //pThread->TxPort1.dwToModule = FicModule;//链式,到Fic模块
                                        //pThread->TxPort1.pPtr = pThread->pRxPort1->pPtr;//传递指针

                                        pThread->TxPort1.bActive = true;//启动命令
                                        pThread->TxPort1.dwToModule = MapModule;//到Map模块
                                        pThread->TxPort1.dwCommand = CMD_Map_Updata;//显示视频数据命令
                                        pThread->TxPort1.pPtr = pThread->pRxPort1->pPtr;//传递指针
                                     }
                                     else
                                     {
                                        pThread->Timer1->Enabled = false;//临时 关闭定时器
                                        pThread->ProgressBar1->Position = 0;//显示进度
                                        pThread->ST100->Caption = " 写Fic文件已完成。";
                                     }
                                    break;
          }
          pThread->pRxPort1->bActive = false;//关闭本次命令处理
       }

       dwResult = WaitForSingleObject(pThread->hEventExit, 1);
       if(dwResult == WAIT_OBJECT_0) break;//退出判断
   }

   return 0;
}

通信端口结构:

struct TCommPort//通信端口结构
{
   bool bActive,//命令有效标志
        bOK;//成功或失败
   DWORD dwToModule,//目的模块
         dwCommand,//命令
         dwParam[8];//参数
   float fParam[2];//浮点参数
   BYTE *pPtr;//指针参数      
   String sStr;//字符串
};

当前中枢模块相关部分:

void __fastcall TAviCentral::Port1To(TCommPort *pInPort)//端口1到
{
   switch(pInPort->dwToModule)
   {
    case OptModule:  memcpy(&TxPort1, pRxPort1, sizeof(TCommPort));//传递到端口1发送
                     break;
    case FicModule:  memcpy(&TxPort2, pRxPort1, sizeof(TCommPort));//传递到端口2发送
                     break;
    case AviModule:  memcpy(&TxPort3, pRxPort1, sizeof(TCommPort));//传递到端口3发送
                     break;
    case MapModule:  memcpy(&TxPort4, pRxPort1, sizeof(TCommPort));//传递到端口4发送
                     break;
   }
}

void __fastcall TAviCentral::Port2To(TCommPort *pInPort)//端口2到
{
   switch(pInPort->dwToModule)
   {
    case OptModule:  memcpy(&TxPort1, pRxPort2, sizeof(TCommPort));//传递到端口1发送
                     break;
    case FicModule:  memcpy(&TxPort2, pRxPort2, sizeof(TCommPort));//传递到端口2发送
                     break;
    case AviModule:  memcpy(&TxPort3, pRxPort2, sizeof(TCommPort));//传递到端口3发送
                     break;
    case MapModule:  memcpy(&TxPort4, pRxPort2, sizeof(TCommPort));//传递到端口4发送
                     break;
   }
}

void __fastcall TAviCentral::Port3To(TCommPort *pInPort)//端口3到
{
   switch(pInPort->dwToModule)
   {
    case OptModule:  memcpy(&TxPort1, pRxPort3, sizeof(TCommPort));//传递到端口1发送
                     break;
    case FicModule:  memcpy(&TxPort2, pRxPort3, sizeof(TCommPort));//传递到端口2发送
                     break;
    case AviModule:  memcpy(&TxPort3, pRxPort3, sizeof(TCommPort));//传递到端口3发送
                     break;
    case MapModule:  memcpy(&TxPort4, pRxPort3, sizeof(TCommPort));//传递到端口4发送
                     break;
   }
}

void __fastcall TAviCentral::Port4To(TCommPort *pInPort)//端口4到
{
   switch(pInPort->dwToModule)
   {
    case OptModule:  memcpy(&TxPort1, pRxPort4, sizeof(TCommPort));//传递到端口1发送
                     break;
    case FicModule:  memcpy(&TxPort2, pRxPort4, sizeof(TCommPort));//传递到端口2发送
                     break;
    case AviModule:  memcpy(&TxPort3, pRxPort4, sizeof(TCommPort));//传递到端口3发送
                     break;
    case MapModule:  memcpy(&TxPort4, pRxPort4, sizeof(TCommPort));//传递到端口4发送
                     break;
   }
}

void __fastcall TAviCentral::ToPort(TCommPort *pInPort, DWORD dwPortNum)//到端口
{
   switch(dwPortNum)
   {
    case OptModule:  Port1To(pInPort);//端口1到
                     break;
    case FicModule:  Port2To(pInPort);//端口2到
                     break;
    case AviModule:  Port3To(pInPort);//端口3到
                     break;
    case MapModule:  Port4To(pInPort);//端口4到
                     break;
   }
}

DWORD WINAPI TAviCentral::CThread(LPVOID lpParam)//工作线程
{
  TAviCentral *pThread = (TAviCentral *) lpParam; DWORD dwResult;

   while(1)
   {
     if(pThread->pRxPort1->bActive)//监视输入端口1,转接输出到其他端口
       {
          pThread->ToPort(pThread->pRxPort1, OptModule);//到端口
          pThread->pRxPort1->bActive = false;//关闭本次命令处理
       }

     if(pThread->pRxPort2->bActive)//监视输入端口2,Fic模块反馈
       {
          pThread->ToPort(pThread->pRxPort2, FicModule);//到端口
          pThread->pRxPort2->bActive = false;//关闭本次命令处理
       }

     if(pThread->pRxPort3->bActive)//监视输入端口3,Avi模块反馈
       {
          pThread->ToPort(pThread->pRxPort3, AviModule);//到端口
          pThread->pRxPort3->bActive = false;//关闭本次命令处理
       }

     if(pThread->pRxPort4->bActive)//监视输入端口4,Map模块反馈
       {
          pThread->ToPort(pThread->pRxPort4, MapModule);//到端口
          pThread->pRxPort4->bActive = false;//关闭本次命令处理
       }

     dwResult = WaitForSingleObject(pThread->hEventExit, 1);
     if(dwResult == WAIT_OBJECT_0) break;//退出判断
   }
   return 0;
}

再次从病理医学网了解到:中枢神经系统像是一部容器巨大的信息加工器,加工的结果可以出现反射活动、产生感觉或记忆。继续改进中枢模块。

经过几天努力,未能实现预置指令链路,还是只能实时单步步进,改进了一点,可以并联执行指令,提高了指令效率,目前进度到临时通过定时器触发播放Avi文件,界面如下:

 通过复制通信结构,实现多指令并联,改进的通信结构代码如下:

struct TSCommPort//单通信端口结构
{
  bool bActive,//命令有效标志
       bOK;//成功或失败

  DWORD dwToModule,//目的模块
        dwCommand,//命令
        dwParam[8],//参数
        dwOptModel;//操作模式

  float fParam[2];//浮点参数

  BYTE *pPtr;//指针参数

  String sStr;//字符串
};

struct TMCommPort//多通信端口结构
{
  bool bActive;//命令有效标志

  DWORD dwCmdCount;//命令数量

  TSCommPort Param[def_MaxCmdCount];
};

通信结构增加dwOptModel操作模式,实现分支控制。改进的播放Avi文件指令链流程图如下:

播放正常。

已实现Fic文件的播放,对流程链路进行了改进和整理,如下图:

对这一架构的探索和设想暂告一段落,初步实现了部分想法,总结如下:

优点:简化理顺函数、模块等相互之间的关系,虽然也很“复杂”,但增强了条理性,尽可能避免“乱麻”等头绪繁乱问题。对于复杂程序,是需要流程图的,链路图类似于流程图,且直接使用,使得问题实际得到简化,流程图虽然“复杂”,但可认为是最简单的。

缺点:正是因为切断了函数、模块等之间的直接调用、依赖,中间加入了通信环节,增加了处理延时,而且是多倍的,因为各模块使用线程“独立自主”处理问题,使得延时问题加重。

展望:通过对这一构想的理解、“进化”,希望建立一套理论、概念,实际应用,例程等,使问题“清晰”,更加“有据可依”。希望引起注意,如果真的有优点,那就有推广意义。

本文结束。 

转载于:https://www.cnblogs.com/hbg200/p/6388527.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值