博文

FAQ 06:如果线程还在运行而我的程序结束了会怎么样?(2007-12-25 15:14:00)

摘要:FAQ 08:如果线程还在运行而我的程序结束了会怎么样?
   程序启动后就执行的那个线程称为主线程(Primary thread)。主线程有两个特点。第一,它必须负 责GUI(Graphic User Interface)程序中的主消息循环。第二,这一线程的结束(不论是因为返回或因为 调用了ExitThread())会使得程序中的所有线程都逼迫结束,程序也因此而结束。其他线程没有机会做清 理工作。
......

阅读全文(2765) | 评论:0

FAQ 05:为什么可以在不结束线程的情况下关闭起handle(2007-12-12 10:56:00)

摘要:             线程的handle是指向“线程核心对象”,而不是指向线程本身。对大部分API而言,这项差异没什么影响。当调用CloseHandle()并给予它一个线程handle时,只不过是表示,希望自己和此核心对象不再有任何瓜葛。CloseHandle()惟一做的事情就是把引用计数减1。如果该值变成0,对象会自动被OS销毁。             “线程核心对象”引用到的那个线程也会令核心对象开启。因此,线程对象的默认引用计数是2当调用CloseHandle()后,引用计数会减1,当线程结束时,引用计数再减1.只有当两件事情都发生了(不管顺序如何)的时候,这个对象才会被真正清除。               “引用计数”机制保证新的线程有个地方可以写下返回值。这样的机制也保证旧线程能够读取那个返回值----只要她没有调用CloseHandle()。                由于被CreateThread()传回的那个handle属进程所有,而非线程所有,所以很可能有一个新产生的线程调用CloseHandle(),取代原来的线程。MS Visual C++ runtime Library中等_beginthread()就是这么做的 。......

阅读全文(3072) | 评论:0

FAQ 04:为什么我应该调用CloseHandle()?(2007-12-12 10:41:00)

摘要:当完成工作后,应该调用CloseHandle释放核心对象 BOOL  CloseHandle( HANDLE    hObject ); 参数    hObject   代表一个已打开对象handle 返回值          如果成功,CloseHandle()返回TRUE。如果失败则返回FALSE,此时可以调用GetLastError()获知失败原因。          如果一个进程没有在结束前针对它所打开的核心对象调用CLoseHandle(),OS会自动把那些对象的引用计数下降1。虽然可以依赖OS做实体(physical)上的清除(cleanup)工作,然而逻辑上的清除工作又是完全不同的一回事,特别是如果你有许多个进程的话。因为OS并不知道对象实际代表什么意义,所以它不可能知道解构顺序是否重要。         如果一个进程常常产生“worker线程”而总不关闭线程的handle,那么这个进程可能最终有数百个甚至更多的个开启的“线程核心对象”留给OS去清理。这样的resource leaks可能会对效率带来负面影响。    另外一点也很重要:不可以依赖“因线程的结束而清理所有被这一线程产生的核心对象”。许多对象,例如文件,是被进程拥有,而非被线程拥有。在进程结束之前不能够清理它们!......

阅读全文(3951) | 评论:0

FAQ 03:线程和进程有何不同?(2007-12-07 13:01:00)

摘要:           从Win32的角度来看,进程含有内存和资源。被进程拥有的内存,理论上可以高达2GB。资源则包括核心对象(如file handles和线程)、USER资源(比如对话框和字符串) 、GDI资源(比如Devic Context和brushes)。         Matt Pietrek在其Windows 95 System Porgramming SECRETS一书中解释进程:就是一大堆对象的拥有权的集合,也就是说,进程拥有对象。进程可以拥有内存(更精确地说是拥有memory context),可以拥有file handles,可以拥有线程,可以拥有一大串DLL模块(被载入这一进程的地址空间中)。 另:内存可以大致分为三种类型: 1、Code         是程序的可执行部分,一定是只读性质。这是CPU唯一允许执行的内存。可执行Windows NT的两种芯片:Intel芯片和RISC芯片 2、Data          是程序中的 所有变量(不包括函数中的局部变量),可以区分为全局变量和静态变量两种。当然,线程也可以使用malloc()或new()动态配置内存。 3、Stack          调用函数时所用的堆栈空间,其中有局部变量。每个线程产生时配有一个堆栈。如果不需要,OS会将它动态扩充。   所有这些内存对进程中的所有线程都是可用的。这在多线程程序中虽然带来了很大的方便,却也带来了很大的灾难。......

阅读全文(2781) | 评论:0

FAQ 02:我可以在Win32s中使用多个线程吗?(2007-12-07 12:36:00)

摘要:        NT有一组全新的API,名为Win32,是Windows 3.1 API的超集。 Win32 API被移植到Windows 3.1上,称为Win32s.不幸的是许多功能无法移植。Win32s即不支持也不支持抢先式多任务也不支持多线程。......

阅读全文(2388) | 评论:0

FAQ 01:合作型多任务与抢先式多任务有和区别(2007-12-04 19:59:00)

摘要:FAQ 01:合作型(coorperative)多任务与抢先式(preemptive)多任务有和区别 Micorsoft Windows的前三个版本(1,2,3)都允许同时执行多个程序,但分享CPU的是程序(而不是OS)的责任。如果有一个程序决定咬住CPU不放,其他程序就停摆了。因此,我们说windows是“合作型多任务”。在2.0和3.0那个时代,还是有许多程序拒绝与别人共享资源,慢慢地大家都进步了,也学习到如何写一个“举止良好”的程序。但这还是花费了大家许多宝贵的精力在诸如“调试”这样的工作上。 由于windows的底层依赖DOS,当格式化一张磁盘或拷贝一个文件到软盘上时,依然让任何其他人都动弹不得。 当此之时,Unix,VMS,AmigaDOS等OS都已经支持一种名为“抢先式多任务”的模式,意思是OS能够强迫应用程序把CPU分享非其他人,程序员不需要什么额外的努力。  ......

阅读全文(3341) | 评论:0

消息分流器、子控件宏、API宏(2007-09-08 19:36:00)

摘要:在本书中,通过使用带消息分流器C/C++编写示例代码,下面向大家介绍这种不大为大家所知但很有用的宏。
 消息分流器定义在VC++中提供的WindowsX.h文件里/通常在Windows.h文件之后紧接着包含这个文件。WindowsX.h文件就是一组#define指令,建立了一组供我们使用的宏。WindowsX.h的宏实际上分为三组:消息分流器、子控件宏和API宏。这些宏以下述的方式为我们提供帮助:
1、利用这些宏可以减少程序中要做的转换(casting)的数量,并可使所要求的转换上无错误的。使用C/C++的Windows编程中一个大的问题是所要求的转换数量。你很难看到一个不要求某种转换的Windows函数调用。但应该尽量避免使用转换,因为转换阻碍编译器发现代码中的潜在错误。一个转换是在告诉编译程序:“我知道我在这里传递了错误的转换,但就要这么做。我知道我在干什么。”当你做了许多转换时,就很容易出错。编译程序应该尽可能对此提供帮助。
2、使代码的可读性更好
3、可简化16位Windows、32位Windows和64位Windows之间的代码移植工作
4、易于理解(只是一些宏)
5、这些宏容易结合到已有的代码中。可以不管老的代码而立即在新的代码中使用这些宏。不必修改整个程序
6、在C/C++代码中都可以使用这些宏,尽管当使用C++类时他们不是必需的
7、如果需要某一个特性,而这些宏不直接支持这个特性,可以根据这个头文件中的宏,很容易地编写自己的宏
8、不需要参照或记住费解的Windows构造。例如,许多Windows中的函数,要求一个long型参数,其中这个长参数的高字(high-word)的值代表一个东西,而低字(long-wrod)又代表另一个东西。在调用这个函数之前,你必须用两个单独的值构造一个long 型值。通常利用Windef.h中MAKELONG宏来完成。我简直记不清有多少次把两个值的次序弄反了,造成对函数传递了一个错误的值。而WindowsX.h中的宏可以帮助我们。 消息分流器  消息分流器(message cracker)使窗口过程的编写更加容易。通常,窗口过程是用一个大的switch语句实现的。在我的经验中,我见过有的窗口过程的switch语句包含了5百多行的代码。我们都知道......

阅读全文(3924) | 评论:0

内存漏洞检查方法(2007-09-08 19:15:00)

摘要:具体地讲检查内存漏洞需要以下几个步骤:
在你所检测的程序段的开始处建立一个CmemoryState对象,调用其成员函数Checkpoint,以取得当前内存使用情况的快照;
在你所检测的程序段的末尾处再建立一个CmemoryState 对象,调用其成员函数Checkpoint ,以取得当前内存使用情况的快照;
再建立第三个CmemoryState 对象,调用其成员函数Difference,把第一个CmemoryState对象和第二个CmemeoryState对象作为其参数.,如果两次内存快照不相同,则该函数返回非零,说明此程序 段中有内存漏洞。下面我们来看一个典型的例子:   // Declare the variables needed #ifdef _DEBUG CMemoryState oldMemState, newMemState, diffMemState; OldMemState.Checkpoint(); #endif // do your memory allocations and deallocations... CString s = "This is a frame variable"; // the next object is a heap object CPerson* p = new CPerson( "Smith", "Alan", "581_0215" ); #ifdef _DEBUG newMemState.Checkpoint(); if( diffMemState.Difference( oldMemState, newMemState ) ) { TRACE( "Memory leaked!\n" ); } #endif  ......

阅读全文(3185) | 评论:0

Win32常用的 类型和宏(2007-07-15 10:58:00)

摘要:Win32常用的 类型和宏 COLORREF
1、结构定义
一个COLORREF 型颜色值是定义了一种颜色的长整数。要求一个颜色参数的GDI函数(比如CreatePen和FloodFill)接受COLORREF值作为参数。
2、结构说明
根据应用程序对COLORREF类型值的不同使用方式,该类型值具有三种不同的形式。它可以定义为下列三种方式之一:
(1)直接定义RGB值
其中低位字节包含了定义红色的相对强度值:第二个字节包含了定义绿色的相对强度值,第三个字节包含了定义蓝色的值,高字节必须为零,单字节的最大值的最大值为FF(十六进制)。下表说明了某些颜色的十六进制值:
----0x000000FF        纯红色
----0x0000FF00        纯绿色
----0x00FF0000        纯蓝色
----0x00000000        黑  色
----0x00FFFFFF       白  色
----0x00808080        淡灰色
RGB宏指令接受红、绿、蓝三种颜色的值,返回一个显示的RGB_COLORREF值。
(2)调色板索引
当指定逻辑调色板的索引时,COLORREF值有如下的16进制形式:0x0100iiii
低位上的两个字节组成了一个16位的整数,它定义了一个逻辑调色板的索引。第三个字节不用,并且必须设置为0,第四个字节(即高位上的字节)必须设置为1。
例如,16进制值0x10000定义了一个索引为0的调色板所代表的颜色;0x010000C定义了一个索引为12的元素所代表的颜色,以此类推。
PALETTEINDEX宏指令接收一个表示逻辑调色板的整数,并返回一个定义为调色板索引的COL......

阅读全文(5871) | 评论:0