阅读 56

代码中的软件工程-从menu小程序到软件工程

参考文献:https://gitee.com/mengning997/se/blob/master/README.md#%E4%BB%A3%E7%A0%81%E4%B8%AD%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B

序言:孟老师的这几节课程中,我的学习一步步从简单走向深入。起初是编译器的安装和提供环境变量然后到配置VScode环境,在这完成之后又知道了如何从搭建一个简单的命令行menu小程序开始,一步步根据软件工程的一般规律开发、完善,最终实现了一个成长起来的menu程序。这其中涉及到了模块化设计、可重用接口、线程安全等议题,下面我来一步步讲解所有涉及到的内容。

1、minGW编译器的安装和环境变量配置以及VScode环境配置

下载地址:http://mingw-w64.org

 安装路径应是全英文的,不然以后在程序的编译中可能会出现莫名其妙的错误

设置环境变量

  最后通过cmd执行gcc -v查看安装和设置环境变量是否成功

 然后就要给VScode配置环境变量,使他可以执行c程序,先在VScode中下载安装C/C++

 虽然VScode中此时有C/C++,但是无法调用minGW编译器,必须要通过tasks.json文件和launch.json文件来使VScode能够调用编译器

 不知道怎么生成tasks.json和launch.json文件没有关系,可以直接点点击运行hello.cpp

 点击之后会出现列表,然后选择gcc.exe

 

 这样tasks.json和launch.json文件就自己生成而且修改好了,并且它的路径是完全正确的

 运行hello.cpp文件,结果输出了hello world!

 

 至此便完成了minGW编译器的安装和环境变量配置以及VScode环境配置

2、模块化设计、可重用接口、线程安全

2.1模块化设计

 模块化是在软件系统设计时保持系统内各部分相对独立,以便每一个部分可以被独立地进行设计和开发。这个做法背后的基本原理是关注点的分离,关注点的分离的思想背后的根源是由于人脑处理复杂问题时容易出错,把复杂问题分解成一个个简单问题,从而减少出错的情形。模块化软件设计最终每一个软件模块都将只有一个单一的功能目标,并相对独立于其他软件模块,使得每一个软件模块都容易理解容易开发。

模块化程度的一个重要指标就是耦合度,耦合度是指软件模块之间的依赖程度,一般可以分为紧密耦合、松散耦合和无耦合。而内聚度是指一个软件模块内部各种元素之间互相依赖的紧密程度。

如何来具体实现模块化呢,就是将数据结构和它的操作与菜单业务处理进行分离处理,尽管还是在同一个源代码文件中,但是已经在逻辑上做了切分,可以认为有了初步的模块化。

 图中:内部代码的逻辑其实并没有什么区别,但是他的数据结构和他的操作声明放到了文件linklist.h中,而他的菜单业务放在了linklist.c中,这样就实现了代码的分离也就是模块化。

linklist.h代码如下,他定义了一个数据结构和相应的操作,也就是声明了接口

 

  linklist.c的代码如下,他是对接口的具体实现,也就是具体的业务

最后是main函数,这是主函数可以调用linklist.h和linklist.c模块


  2.2可重用接口

接口就是互相联系的双方共同遵守的一种协议规范,在我们软件系统内部一般的接口方式是通过定义一组API函数来约定软件模块之间的沟通方式。

软件设计中的模块化程度便成为了软件设计有多好的一个重要指标,一般我们使用耦合度(Coupling)和内聚度(Cohesion)来衡量软件模块化的程度,耦合度是指软件模块之间的依赖程度,一般可以分为紧密耦合(Tightly Coupled)、松散耦合(Loosely Coupled)和无耦合(Uncoupled)。一般在软件设计中我们追求松散耦合,因为这样的话接口就可以重复使用了。

要想使接口可重用,就得使接口通用化,通用接口定义的基本方法:参数化上下文, 移除前置条件,简化后置条件。

在lab4中,每一次都得自己去获取详细的前置条件,所以并没有十分通用

  在lab5.1中,它已经移除了前置条件,不需要具体内容,用节点代替即可,同时使用了callback函数,他能使接口更加通用,因为卧底函数可是时时传来收集的情报

 在lab5.2中,前面的方式中用户程序的卧底函数需要向基地查询目标信息,也就是使用了全局变量cmd。与现实世界的情况类似这样会大大增加卧底暴露的风险,为了降低风险增加了args参数,这样在派遣卧底的同时指定了目标情报的内容,卧底在行动过程中就不需要和基地建立联系,只有在搜集到目标情报args时才向基地报道完成任务,这就使的接口更加通用

  2.3线程安全

线程:线程(thread)是操作系统能够进行运算调度的最小单位。它包含在进程之中,是进程中的实际运作单位。一个线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。一般默认一个进程中只包含一个线程。 操作系统中的线程概念也被延伸到CPU硬件上,多线程CPU就是在一个CPU上支持同时运行多个指令流,而多核CPU就是在一块芯片上集成了多个CPU核,比如4核8线程CPU芯片就是在集成了4个CPU核,每个CPU核上支持2个线程

变量的归属:变量都存储在函数调用堆栈空间中,因此函数参数和局部变量也是线程独自拥有的。除了函数调用堆栈空间,同一个进程的多个线程是共享其他进程资源的,比如全局变量是多个线程共享的。

可重入函数:可重入(reentrant)函数可以由多于一个任务并发使用,而不必担心数据错误。可重入函数可以在任意时刻被中断,稍后再继续运行,不会丢失数据。可重入函数要么使用局部变量,要么在使用全局变量时保护自己的数据。

线程安全:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

线程安全的条件:若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行读写操作,一般都需要考虑线程同步,否则就可能影响线程安全。

函数的可重入性与线程安全之间的关系:可重入的函数不一定是线程安全的,可能是线程安全的也可能不是线程安全的;可重入的函数在多个线程中并发使用时是线程安全的,但不同的可重入函数(共享全局变量及静态变量)在多个线程中并发使用时会有线程安全问题;

 在lab5.1文件夹的linktable.h中,引入了头文件#include ,并且在链表数据结构中,增加了一个信号量mutex

 此时,我们将链表作为了一种临界资源,按照信号量机制,对其进行互斥访问,即PV操作。

 图中的lock操作和unlock操作,就实现了我们上述提到的PV操作,实现了临界资源的互斥访问,这样就是线程安全。

 3、总结

本章的学习让我们知道了代码是如何一步步健壮起来的以及模块化、可重用接口、线程安全是如何在代码发展过程中起作用的。

 

 

 

 

 

 

 

 

 

 

原文:https://www.cnblogs.com/xctang/p/13918279.html

文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐