代码中的软件工程--以menu项目分析
一、C/C++环境配置
1.安装Mingw,安装完成后自行加入系统环境变量,并使用命令提示符输入gcc -v指令,查看是否安装成功。

2.VSCode配置
打开launch.json进行环境配置,主要的配置指令如下:
{
"name": "编译",
"type": "cppvsdbg",
"request": "launch",
"program": "cmd",
"args": [
"/C"
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"internalConsoleOptions" :"openOnSessionStart",
"preLaunchTask": "C/C++: gcc.exe build active file"
},
{
"name": "执行",
"type": "cppvsdbg",
"request": "launch",
"program": "cmd",
"args": [
"/C",
"${fileDirname}\\${fileBasenameNoExtension}.exe",
"&",
"pause"
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true
}
配置完成后我们打开hello.c文件进行测试,在VSCode左上角依次选择“编译”与“执行”按钮

![]()
最终我们得到执行的结果:

至此,环境配置的步骤完成!
二、基于menu的软件工程分析
1.代码的模块化
模块化程序设计是指每个小程序模块完成一个确定的功能,并在这些模块之间建立必要的联系,通过模块的互相协作完成整个功能的程序设计方法。由此可见,模块化编程强调的是逻辑和功能,而不是编程语句本身。跟常规编程不一样的是,模块化编程最大化的实现了“代码内嵌”,很多固定的和通用的代码被集成在模块内部,从而形成了类似于“黑匣子”的功能块,用户只要掌握模块化的输入输出及控制就可以很好进行应用设计。这一点非常适合初学者或者非编程专业人员。
在该项目中,lab4文件夹下头文件linktable.h、linktable.c与menu.c就体现出了代码模块化的思想,即将数据结构以及它的操作与菜单业务的进行了隔离的处理,也即将其放至于不同的文件中。
首先我们来看linktable.h头文件的关键代码:
/*
* LinkTable Node Type
*/
typedef struct LinkTableNode
{
struct LinkTableNode * pNext;
}tLinkTableNode;
/*
* LinkTable Type
*/
typedef struct LinkTable
{
tLinkTableNode *pHead;
tLinkTableNode *pTail;
int SumOfNode;
pthread_mutex_t mutex;
}tLinkTable;
/*
* Create a LinkTable
*/
tLinkTable * CreateLinkTable();
/*
* Delete a LinkTable
*/
int DeleteLinkTable(tLinkTable *pLinkTable);
/*
* Add a LinkTableNode to LinkTable
*/
int AddLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);
/*
* Delete a LinkTableNode from LinkTable
*/
int DelLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);
/*
* get LinkTableHead
*/
tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable);
/*
* get next LinkTableNode
*/
tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);
这里使用结构体构造了LinkTableNode、LinkTable两类结构,根据代码我们可知,结构分别为单向链表与双向链表,接着在此基础上完成了对函数CreateLinkTable、DeleteLinkTable、AddLinkTableNode、DelLinkTableNode、GetLinkTableHead、GetNextLinkTableNode的定义,具体实现则在linktable.c中。这些函数都是对于LinkTableNode、LinkTable结构的一系列操作,从函数名我们也可见,一个函数能够实现一项具体功能(e.g:调用CreateLinkTable函数可创建LinkTable结构),同时通过这些函数的调用,也即功能的相互组合,便能实现具体的菜单业务,这也体现出模块化思想中“一个软件模块只做一件事,只完成一个主要功能点或者一个软件特性”这一要义。
2.可重用软件模块接口
我们再一次关注linktable.h头文件,在这个文件中定义了大量的可看作接口的可重用函数,我们以其中一个为例,进行解析。
解析:
1.根据函数名,我们可以清晰的知道此函数用于删除一个LinkTable的链表
2.若此时需要进行删除,需要保证传入的指针pLinkTable不为空,否则会返回-1;
3.使用该接口时,需遵守tLinkTableNode及tLinkTable数据结构的定义
4.实现该接口的功能逻辑是逐项删除LinkTable中的LinkTableNode,直至为空,同时在最后将LinkTable的成员变量进行初始化。
三、线程安全
当程序同时满足以下两个条件时:
1.多个线程在操作共享的数据。
2.操作共享数据的线程代码有多条。
当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。
在该项目中许多地方也涉及到了多线程对临界资源的访问,由于访问资源临界区涉及到线程安全的问题,在项目也通过采取锁机制,实现对临界资源的互斥访问,保证线程安全。
例如linktable.c中的AddLinkTableNode函数
/*
* Add a LinkTableNode to LinkTable
*/
int AddLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode)
{
if(pLinkTable == NULL || pNode == NULL)
{
return FAILURE;
}
pNode->pNext = NULL;
pthread_mutex_lock(&(pLinkTable->mutex));
if(pLinkTable->pHead == NULL)
{
pLinkTable->pHead = pNode;
}
if(pLinkTable->pTail == NULL)
{
pLinkTable->pTail = pNode;
}
else
{
pLinkTable->pTail->pNext = pNode;
pLinkTable->pTail = pNode;
}
pLinkTable->SumOfNode += 1 ;
pthread_mutex_unlock(&(pLinkTable->mutex));
return SUCCESS;
}
若我们想要向Linktable中添加一个LinkTableNode,函数中首先 通过代码pthread_mutex_lock(&(pLinkTable->mutex))对后面的临界区(即添加LinkTableNode)上锁,以防止多个线程同时对Linktable添加节点。当该线程对Linktable修改完成后通过函数pthread_mutex_unlock(&(pLinkTable->mutex))释放锁,允许了别的线程接着进行修改,这样实现了对临界资源的互斥访问,保证了线程的安全。
浙公网安备 33010602011771号