重要的概念:
一:当今的操作系统能让磁盘空间看起来像内存一样。磁盘上的文件一般被称为页交换文件 (paging file) ,其中包含虚拟内存,可供任何进程使用。
二:最好是把物理存储器看成是保存在磁盘 ( 通常是硬盘 ) 上的页交换文件中的数据。
三:使用内存的方式有三种:
虚拟内存:要考虑分配粒度及边界但是速度快
内存映射文件:要考虑分配粒度及边界但是速度快
堆:不用考虑分配粒度及边界但是速度慢
四:默认堆:( 1M )
16 位老式的堆函数 LoaclAlloc, GlobalAlloc. 是从进程的默认堆中进行分配的。
----------------------------------------------------------------------------------------------------------------------
DLL 的高级技术:
1:) PCSTR 意味做只能接受 ANSI 字符串,决不能将 Unicode 字符串传递给它。 如
FARPROC GetProcAddress(HMODULE hModule, LPCTSTR lpProcName);
2:)DLL 显示链接不需要拷贝 lib 文件;只有在静态链接的情况下再使用。
3:)DLL 总结:
DLL 显式,隐式两种方式的链接,显式 [LoadLibrary, GetProcAddress, FreeLibrary], 只需要 .dll., 隐式: lib 文件。
在显示链接中, c++ 运行期库会调用 DllMain 函数。 DllMain 中有四个参数:
case DLL_PROCESS_ATTACH:
初次调用的时候 LoadLibrary 的时候,所以主线程从这里开始运行。
case DLL_THREAD_ATTACH:
创建新线程的时候开始调用这个函数
case DLL_THREAD_DETACH:
线程终止运行的时候调用,但是如果调用 TerminateProcess 函数不会调用。
case DLL_PROCESS_DETACH:
线程终止运行的时候调用,但是如果调用 TerminateThread 函数不会调用。
不要在 dllMain 中调用 wait*, DllMain 的执行是顺序的。 DllMain 函数最好一次只有一个线程执行,以免发生死锁现象。
3:)导出类的样式代码:
Dll 部分[complex.h]
#ifdef COMPLEX_EXPORTS
#define COMPLEX_API __declspec(dllexport)
#else
#define COMPLEX_API __declspec(dllimport)
#endif
// This class is exported from the complex.dll
class COMPLEX_API CComplex
{
// TODO: add your methods here.
public:
CComplex(void);
};
extern "C" __declspec(dllexport) CComplex* CreateObject();
----------------------------------------------------------------------------------------------------------------------
[ complex.cpp]
#include "stdafx.h"
#include "complex.h"
#include <stdio.h>
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
printf("DLL_PROCESS_ATTACH/n");
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// This is the constructor of a class that has been exported.
// see complex.h for the class definition
CComplex::CComplex()
{
printf("construct a object");
return;
}
CComplex* CreateObject()
{
printf("CreateObject/n");
return new CComplex();
}
----------------------------------------------------------------------------------------------------------------------
应用端:[TestComplex.cpp]
#include "stdafx.h"
#include "complex.h"
#include <wtypes.h>
int main(int argc, char* argv[])
{
typedef CComplex* (*PFUNCOMPLEX)();
HINSTANCE hInst = LoadLibrary("complex.dll");
if (NULL == hInst)
{
printf("Fail to load dll/n");
return 0;
}
PFUNCOMPLEX pfnComplex = (PFUNCOMPLEX)GetProcAddress(hInst, "CreateObject");
CComplex *pObj = pfnComplex();
FreeLibrary(hInst);
printf("Hello World!/n");
return 0;
}
4:)利用dumpbin工具查看导出符号信息。
----------------------------------------------------------------------------------------------------------------------
线程本地存储器 [TLS] :动态 TLS 和静态 TLS
将数据与索引联系起来有以下两种方式 :
动态 TLS : TLSAlloc 会去查询一个 Free 标志并将其改为 INUSE ,同时为每个线程保留该返回的索引,数据就被保存在这个索引中。这样就可以保证别的线程不会同时占用同一个索引号。这个函数还会在其返回之前,遍历该进程中的所有线程为每个线程新分配索引号处设置数据 0 。
静态 TLS :声明方式: --declspec(thread) 数据类型 变量名;这种形式只能用于全局变量不能应用与局部变量,这也很容易理解,因为局部变量都是与线程相关联的,静态 TLS 数据会被放置在 .tls 的节中。一个线程的 TLS 数据不会影响另一个线程的数据。
----------------------------------------------------------------------------------------------------------------------
结构化异常处理程序与异常处理程序:
结构化异常处理程序 :
1: 由编译器来执行。
2: 有局部展开概念 .
3: 应尽量避免在 __try 及 __finally 中使用过早退出语句 . 如 return, goto, contrinue, break 等。对于这种情况应该使用 __leave 关键字来代替 ,__leave 的调用将直接转向 __try 的右括号且不会破坏 __try…__finally… 的执行流。
4 : ExitThread, ExitProcess, TerminateThread, TerminateProcess 会立即结束线程而不会调用到 __finally 的代码。
5 :文法结构 :
__try
{
Guarded body
}
__finally
{
Terminate handle
}
异常处理程序:
1: 由操作系统执行。
2 :无局部展开概念。没有合适异常发生 exception 部分代码不会执行。
3 :文法结构 :
__try
{
Grarded body
}
__exception (exception filter)
{
}