用一个例子来说明程序开发过程中的粒度和弹性控制
前言
弹性和粒度是程序开发中的两个重要概念,对这两个方面的控制直接决定一个程序员所能控制的程序的规模.如果粒度太粗,则会倒至模块自身规模太大难以维护.如果粒度太细则模块在复用的时候就会很繁琐.
一个好的思路是将模块的粒度尽量的做的细致,但这些细致的模块有很好的弹性.也就是说虽然粒度很精细但适应能力很强.
下面以一个例子来说明一下上面所说的好思路.这个例子以编程中常见的多线程编程中的临界段来处理来逐步阐述一个好的粒度的弹性控制.
毫无弹性和粒度可言的编程模型.
这个模型以系统提供的临界段编程接口为基础直接使用临界段,不进行任何封装.它的编程模式大致如下:
// 全局的临界段声明
CRITICAL_SECTION CriticalSection;
void test()
{
// 对临界段进行初始化
// ** 注意初始化在整个程序期间只需进行一次
InitializeCriticalSection(&CriticalSection);
// 以函数ThreadProc为入口建立一些线程,或以和函数ThreadProc访问相同共享资源的线程
// 释放临界段
DeleteCriticalSection(&CriticalSection);
}
DWORD WINAPI ThreadProc( LPVOID lpParameter )
{
// 进行入临界段.
EnterCriticalSection(&CriticalSection);
// 访问共享资源
// ........
///////////
// 离开临界段.
LeaveCriticalSection(&CriticalSection);
return 0;
}
这种编程模式下有一个很不方便的地方,当线程函数ThreadProc有多个return语句时,很容易漏过LeaveCriticalSecton的调用.这会倒至这个临界段所保护的资源再也不能进行访问.
安全使用临界段的类封装(加入些粒度控制)
为了解决漏过离开临界段调用的问题,我们需要一种机制来保证离开临界段的调用,而不是由使用它程序员来负责这个问题.下面是改进后的程序模式:
// 全局的临界段声明
CRITICAL_SECTION CriticalSection;
// 保证安全使用临界段的类
struct SafeCriticalSection
{
SafeCriticalSection()
{
// 进行入临界段.
EnterCriticalSection(&CriticalSection);
}
~SafeCriticalSection()
{
// 离开临界段.
LeaveCriticalSection(&CriticalSection);
}
};
void test()
{
// 对临界段进行初始化
// ** 注意初始化在整个程序期间只需进行一次
InitializeCriticalSection(&CriticalSection);
// 以函数ThreadProc为入口建立一些线程, 或以和函数ThreadProc访问相同共享资源的线程
// 释放临界段
DeleteCriticalSection(&CriticalSection);
}
DWORD WINAPI ThreadProc( LPVOID lpParameter )
{
SafeCriticalSection useCriticalSection;
// 访问共享资源
// ........
///////////
return 0;
}
在这个模式下,所使用的临界段的EnterCriticalSectoin的调用和LeaveCriticalSectioin的调用被封装在类SafeCriticalSection的构造和析构函数中.使用临界段CriticalSection时再也不用为漏掉对LeaveCriticalSection的调用而小心翼翼了.
到这里我们可以说对临界段CriticalSection的使用有些粒度了.可是这个模式下还有一个不足之处,那就是类SafeCriticalSection与全局变量CriticalSection的联系太紧密了.如果要使用另外一个临界段,我们的类SafeCriticalSection就无能为力了.也就是说这个模式没有弹性.
为粒度加入些弹性
为了让我们的类SafeCriticalSectoin有一定的适应能力我们要为这个类加入一些有弹性的设计.现在的新的程序模式如下:
// 全局的临界段声明
CRITICAL_SECTION CriticalSection;
// 保证安全使用临界段的类
struct SafeCriticalSection
{
SafeCriticalSection(LPCRITICAL_SECTION section):m_critSect(section)
{
// 进行入临界段.
EnterCriticalSection(m_critSect);
}
~SafeCriticalSection()