上下两解放军拿红旗挥舞,看图猜成语人钱蛋鸡

把九个东西(什么都行)摆成3×3 猜的人不看 让另猜成语一个人在跑指其中一个 告诉猜的人 用的哪只手和那 - 游戏问答频道_单机游戏下载网
把九个东西(什么都行)摆成3×3 猜的人不看 让另猜成语一个人在跑指其中一个 告诉猜的人 用的哪只手和那
快中慢三辆车同时猜成语一个人在跑从同一地点出发,沿同一条公路追一个人。速度都不变。这三辆车分别用了6分钟疯狂猜成语一个人跑、10分钟、12分钟追上人,现在知道快车的一个人在看书猜成语速度是24千米,中车是20千米。慢车的速度疯狂猜图一个人是多少?
快中慢三辆车同时猜成语一个人在跑从同一地点出发,沿同一条公路追一个人。速度都不变。这三辆车分别用了6分钟疯狂猜成语一个人跑、10分钟、12分钟追上人,现在知道快车的一个人在看书猜成语速度是24千米,中车是20千米。慢车的速度是多少? 15
最好有算式!一只虎一个人猜成语先谢啦!
不区分大小写匿名
慢车速度19千米。(20*10-24*6)/(10-6)=14千一个人拿红旗猜成语米(人的速度)
再设慢车速度为X,那么
(144-6*14)/一个人丢骨头猜成语(X-14)=12
60/(X-14)=12
60=12X-168
X=(168-60)/12
X=19楼主给我分
(20*10-24*6)/(10-6猜成语一个人在跑)=14千米
再设慢车速度为X,那么
(144-6*14)/一个人丢骨头猜成语(X-14)=12
60/(X-14)=12
60=12X-168
X=(168-60)/12
慢车速度19千米
等待您来回答
学习帮助领域专家
当前分类官方群专一个人在看书猜成语业解答学科习题,随时随地的答疑辅疯狂猜图一个人导有了宝宝以后,我就在家里,现在也是我在带宝宝,老公一个人赚一个人一支笔猜成语钱三个人用,每个月的开销都很大。我又舍不得离开一个人大肚子猜成语宝宝出去上班,不知道宝妈们有疯狂猜成语一个人没有什么建议,让我能在家里带_育一只虎一个人猜成语儿问答_宝宝树
有了宝宝以后,我就在家里,现在也是我在带宝宝,老公一个人赚一个人一支笔猜成语钱三个人用,每个月的开销都很大。我又舍不得离开一个人大肚子猜成语宝宝出去上班,不知道宝妈们有疯狂猜成语一个人没有什么建议,让我能在家里带
宝宝还能赚到钱。
当时年龄:
亲,我也是1,试试开个淘宝点吧,可能会缓解一下
之前有听说做网上帮网疯狂猜成语一个人跑店刷信誉的可以挣些钱,具体的没有了解过。
亲,您迟早是要上班的呢,不过自己带宝一个人在看书猜成语宝就放心一些,如果有人跟您说可以赚钱什么疯狂猜图一个人的我觉得您也不要太相信了,小心被骗哦,您在附近弄个一个人一支笔猜成语手工做就好了。
其实全职妈妈最重要的任务一个人大肚子猜成语就是好好的把宝宝平安带大,经济条件虽然有限,但与孩子的健疯狂猜成语一个人康成长相比,还是孩子更重要,好好带三年,等宝宝上幼儿园以一只虎一个人猜成语后你就可以上班了,坚持一下就过去了。
宝妈不要担心,那只是一段时间,宝爸会努力的。其实我现在也是啊,宝宝需要啊,钱是挣不完的。等宝宝大点就可一个人拿红旗猜成语以去工作了啊
我也是在家看孩子,我两个宝宝,就老公自己工作。
除非是家里有一个人丢骨头猜成语老人帮忙带,下班自己带,不让宝宝这么小猜成语一个人在跑也离不开妈妈,等到两周岁,可以上小小班疯狂猜成语一个人跑再去上班
你好,宝妈可以去找一个人在看书猜成语点手工活做的,或者是让你婆疯狂猜图一个人婆帮忙带宝宝,你就在家附近找点轻一个人一支笔猜成语松的工作做下、
这个难度还有点大哦,一般公司上班一个人大肚子猜成语都需要到公司,除非宝妈自疯狂猜成语一个人己干点啥
亲,这个是比较少的哦,除非自己领手工活自一只虎一个人猜成语己回家做才有的哦,不然的话,现在带宝宝也没什么一个人拿红旗猜成语精力能够做别的哦,这个你可以考虑一个人丢骨头猜成语之前是做什么的,能不能拿活回家做的哦。当前位置:
理解 COM 套间
理解 COM 套间
发布日期: 10:15
浏览次数:20246次
标  签:COM
文章评分:5.0
操  作:
称号:未设置简介:...
文章概要:
大学毕业前的猜成语一个人在跑最后一学期,在一家公司实习,当时的工作需要用到一疯狂猜成语一个人跑些操作系统提供的组件。那时候只知道一个人在看书猜成语COM这个名词,并不知道到底疯狂猜图一个人是怎么回事,只知道上网到处找别人一个人一支笔猜成语的源码解决自己的问题;那段日子到现在回一个人大肚子猜成语忆起来都是灰色的,每天呆坐在电脑前,一个网站一个网站的疯狂猜成语一个人查找自己需要的源码。但并不清楚自己一只虎一个人猜成语到底在做什么;那时候对自己能不能成为一个人拿红旗猜成语一个程序员充满了怀疑。在实习结束返一个人丢骨头猜成语校的火车上,一夜间,我把一本《COM本质猜成语一个人在跑论》翻看了120多页。当我和当时的女友吹嘘自己疯狂猜成语一个人跑一夜可以看100多页书的时候,她马上问我:看懂多一个人在看书猜成语少?当时我哑口无言。她忍受不了我那段疯狂猜图一个人日子的失落和抱怨,从那时候起,我们结束了那一个人一支笔猜成语段简短的感情。到如今我还在一个人大肚子猜成语一个人漂泊着,而上周她成为疯狂猜成语一个人了别人的妻子。想不到用什么方式去纪念我迄一只虎一个人猜成语今为止经历过的唯一一段感情,我和她的感情并不完一个人拿红旗猜成语全是因为COM结束的,但由于对COM的迷惑,使我走向了迷茫,失落;对自己失去了信心,在她面前变成了一一个人丢骨头猜成语个悲观失望的人。写这篇文章权当对这猜成语一个人在跑份感情的一份纪念吧。
大学毕业前的猜成语一个人在跑最后一学期,在一家公司实习,当时的工作需要用到一疯狂猜成语一个人跑些操作系统提供的组件。那时候只知道一个人在看书猜成语COM这个名词,并不知道到底疯狂猜图一个人是怎么回事,只知道上网到处找别人一个人一支笔猜成语的源码解决自己的问题;那段日子到现在回一个人大肚子猜成语忆起来都是灰色的,每天呆坐在电脑前,一个网站一个网站的疯狂猜成语一个人查找自己需要的源码。但并不清楚自己一只虎一个人猜成语到底在做什么;那时候对自己能不能成为一个人拿红旗猜成语一个程序员充满了怀疑。在实习结束返一个人丢骨头猜成语校的火车上,一夜间,我把一本《COM本质猜成语一个人在跑论》翻看了120多页。当我和当时的女友吹嘘自己疯狂猜成语一个人跑一夜可以看100多页书的时候,她马上问我:看懂多一个人在看书猜成语少?当时我哑口无言。她忍受不了我那段疯狂猜图一个人日子的失落和抱怨,从那时候起,我们结束了那一个人一支笔猜成语段简短的感情。到如今我还在一个人大肚子猜成语一个人漂泊着,而上周她成为疯狂猜成语一个人了别人的妻子。想不到用什么方式去纪念我迄一只虎一个人猜成语今为止经历过的唯一一段感情,我和她的感情并不完一个人拿红旗猜成语全是因为COM结束的,但由于对COM的迷惑,使我走向了迷茫,失落;对自己失去了信心,在她面前变成了一一个人丢骨头猜成语个悲观失望的人。写这篇文章权当对这猜成语一个人在跑份感情的一份纪念吧。
企者不立,跨着不行。很多格言都告诉我们做什一个人在看书猜成语么事情都必须从基础开始,对COM的理解也疯狂猜图一个人是这个道理。当三年前我看《COM 本质论》的时候,对虚函数也只一个人一支笔猜成语是一知半解,只是知道通过它一个人大肚子猜成语可以实现多态。但到底怎么实疯狂猜成语一个人现就不清楚了。看不懂COM太正常了。知道看过Stanley B.Lippman的《Inside the C++ Object Model》,对C++的内存结构一只虎一个人猜成语有了基本的理解,我才明白了接口的意义。这篇文章是写一个人拿红旗猜成语给初学者的,顺便给大家一些建议,如果一本书你一个人丢骨头猜成语看不懂的时候,可以先放放,先找一些基础猜成语一个人在跑的读物来看看。这样可以少走一些弯路。
Don Box 在《COM 本质论》中说,对接口,类对象和套间有疯狂猜成语一个人跑了彻底的理解,那么使用COM,没有翻不过去的山头。如果你对C++有一个人在看书猜成语深入的理解,那么《COM本质论》中对接疯狂猜图一个人口和类对象的阐述很清晰,理解并不困难。但套间是一个比一个人一支笔猜成语较抽象的概念,而书上对这部分一个人大肚子猜成语只是理论的叙述,没有提供具体的例子,理解起来就更困难了。在此我把自己找到的一些例疯狂猜成语一个人子和自己的理解总结以下,以期给初学者提供一只虎一个人猜成语一些入门的方法。闲话打住,开始正文吧。
一、关于多线一个人拿红旗猜成语程(Multithreading)
子曰:本立道生。也就是说我们明白一个人丢骨头猜成语事物所存在的原因,自然也就明白事猜成语一个人在跑物是怎么回事了。如果我们清楚了套疯狂猜成语一个人跑间(Apartment)的产生原因,再去理解套间,就容易许多了。我们先来看看,为什么需要套间?套间是为解一个人在看书猜成语决多线程中使用组件而产生的,首先我们来了疯狂猜图一个人解一下多线程。&
1、理解进程(Processes一个人一支笔猜成语)和线程(Threading)
理解线程,先从进程(一个人大肚子猜成语Processes)开始,一般书上对进程的疯狂猜成语一个人描述都比较抽象,都说进程是一个运一只虎一个人猜成语行的程序的实例,进程拥有内存,资源。我这儿试着用一段汇编一个人拿红旗猜成语程序来解释一下进程,看看能不能帮你一个人丢骨头猜成语加深一下印象。我们先来看一段简单的汇编猜成语一个人在跑程序(你不理解汇编的话,建议找本书看看,一点不懂汇编,很难对其它高级语疯狂猜成语一个人跑言有太深的理解)。
; 汇编程序示例
data_seg segment
;定义数据段
data_seg ends
stack_seg segment ;定义堆栈
   dw 128 dup(0)
tos label word
statck_seg ends
code1 segment
;定义代码段
main proc far
assume cs:ccode,data,seg,ss:stack_seg
move ax,stack_seg
;将定义的堆栈段一个人在看书猜成语的地址保存到ss
mov sp,offset tos
;将堆栈的最后疯狂猜图一个人地址保存到sp,堆栈是从下到一个人一支笔猜成语上访问的
push ds  ;保存旧的数据段
mov ax,data_seg
;将定义的数据一个人大肚子猜成语段保存到ds
;调用子函数
;其它操作省略
ret   ;返回到系统
fact proc near    
;子函数定义
;具体操作省略
ret  ;返回到调用处
code1 ends
示例1:汇编疯狂猜成语一个人程序结构
从以上程序我们看到,一个程序可以一只虎一个人猜成语分为代码段,数据段,堆栈段等几部分。汇编编译器在编译的时候会将这些文件转化为成一个标准格式(在windows下一个人拿红旗猜成语被称为PE文件格式)的文件(很多时候可执行文件被命名为二进制文件,我不喜欢这个名字,我觉得它容易给人误解;事实上计算机上所有的一个人丢骨头猜成语文件都是0和1组成的,都是二进制文件;真正不同的就是处猜成语一个人在跑理这些文件的方式;EXE文件需要操疯狂猜成语一个人跑作系统来调用,TXT文件需要写一个人在看书猜成语字本来打开;但其本质上并疯狂猜图一个人没有什么不同,只是在不同的组合上,二进制数有不一个人一支笔猜成语同的意义)。该文件格式会把我们的代码一个人大肚子猜成语按格式安放在不同的部分。程序必须在内存中,才可以执行。在程序运行前,操作系统会按照标准格式疯狂猜成语一个人将这些内容加载到内存中。这些数据加载到内存中一只虎一个人猜成语也需要按照一定的格式,CPU提供了DS,CS,SS等段寄存器,这样代码段的开始一个人拿红旗猜成语位置需要被CS指定,数据段的开始位置一个人丢骨头猜成语需要用DS来指定,SS需要指向堆栈猜成语一个人在跑的开始位置等。在DOS下,每次只能运行一个程序,这些内容基本疯狂猜成语一个人跑构成了进程。但在Windows下,丰富了进程的内容,还包括一些数据结构用来维一个人在看书猜成语护我们程序中用到的图标,对话框等内容,以及线程。其实进程就是程序在疯狂猜图一个人内存中的组织形式,有了这样的组织形式,程序才可能运行。也就是说,当程序加载到一个人一支笔猜成语内存中去后,就形成了一个进程。
我们知道,CPU中拥有众一个人大肚子猜成语多的寄存器,EAX,EBX等,而CPU的指令一般都是疯狂猜成语一个人通过寄存器来实现的。其中有一个寄存一只虎一个人猜成语器叫做EIP(Instruction Pointer,指令寄存器),程序的有序执行,是靠它来完成的。看下面的例子:
mov eax,4
mov ebx,5
假如我们的程一个人拿红旗猜成语序运行到mov eax,4,那么EIP就会指向该句代一个人丢骨头猜成语码所在的内存的地址。当这行代码执猜成语一个人在跑行完毕之后,那么EIP会自动加一,那么它就会指向mov ebx,4。而程序的执行就是靠EIP的不疯狂猜成语一个人跑断增加来完成的(跳转的话,EIP就变成了跳一个人在看书猜成语转到的地址)。在Windows系统下,进程并不拥有EIP,EAX,那么只有进程,一个程序就无法运行。而拥有这些寄疯狂猜图一个人存器的是线程,所以说进程是静态的。
我们知道一个CPU一个人一支笔猜成语下只有一个EIP,一个EAX,也就是说同一时刻只能一个人大肚子猜成语有一个线程可以运行,那么所说的多线程又是什么呢?事实疯狂猜成语一个人上同一时刻也只有一个线程在运行,每个线程运行一只虎一个人猜成语一段时间后,它会把它拥有的EIP,EAX等寄存器让出来,其它线程占有一个人拿红旗猜成语这些寄存器后,继续运行。因为这段时间很短,所以我们感觉不出来。这样我们就可以在一个人丢骨头猜成语一边听音乐的时候,一边玩俄罗斯方块了。为了实现不同的猜成语一个人在跑线程之间的转换,CPU要求操作系统维护一份固定格式疯狂猜成语一个人跑的数据(该数据存在于内存中),这份数据一个人在看书猜成语叫做Task-State Segment(TSS),在这份数据结构里,维护着线程的EAX,EIP,DS等寄存器的内容。而CPU还有一个疯狂猜图一个人寄存器叫做Task Register(TR),该寄存器指向当前正一个人一支笔猜成语在执行的线程的TSS。而线程切换事实上就一个人大肚子猜成语是TR指向不同的TSS,这样CPU就会自动疯狂猜成语一个人保存当前的EAX,EBX的信息到一只虎一个人猜成语相应的TSS中,并将新的线程的信一个人拿红旗猜成语息加载到寄存器。
事实上线程不过一个人丢骨头猜成语上一些数据结构,这些结构保存了程序执猜成语一个人在跑行时候需要的一些信息。我们可以在windows提供的头疯狂猜成语一个人跑文件中找到一些影子,安装VC后在它的include一个人在看书猜成语目录下有一个Winnt.h文件。在该文件中,我们可以找到疯狂猜图一个人这样一个struct(_CONTEXT)。这就是线程切换时需要的数据结构(我一个人一支笔猜成语不确定Windows内部是否用的就是这个结构,但应该和这份数一个人大肚子猜成语据相差无几)。
// Context Frame
This frame has a several purposes: 1) it is used as an argument to
NtContinue, 2) is is used to constuct a call frame for APC delivery,
and 3) it is used in the user level thread creation routines.
The layout of the record conforms to a standard call frame.
typedef struct _CONTEXT {
  // The flags values within this flag control the contents of
  // a CONTEXT record.
  // If the context record is used as an input parameter, then
  // for each portion of the context record controlled by a flag
  // whose value is set, it is assumed that that portion of the
  // context record contains valid context. If the context record
  // is being used to modify a threads context, then only that
  // portion of the threads context will be modified.
  // If the context record is used as an IN OUT parameter to capture
  // the context of a thread, then only those portions of the thread''s
  // context corresponding to set flags will be returned.
  // The context record is never used as an OUT only parameter.
  DWORD ContextF
  // This section is specified/returned if CONTEXT_DEBUG_REGISTERS一只虎一个人猜成语疯狂猜成语一个人 is
  // set in ContextFlags.
Note that CONTEXT_DEBUG_REGISTERS一只虎一个人猜成语疯狂猜成语一个人 is NOT
  // included in CONTEXT_FULL.
  // This section is specified/returned if the
  // ContextFlags word contians the flag CONTEXT_FLOATING_POINT一个人拿红旗猜成语.
  一个人丢骨头猜成语FLOATING_SAVE_AREA FloatS
  // This section is specified/returned if the
  // ContextFlags word contians the flag CONTEXT_SEGMENTS.
  // This section is specified/returned if the
  // ContextFlags word contians the flag CONTEXT_INTEGER.
  // This section is specified/returned if the
  // ContextFlags word contians the flag CONTEXT_CONTROL.
SegCs;    
// MUST BE SANITIZED
EF    
// MUST BE SANITIZED
  // This section is specified/returned if the ContextFlags word
  // contains the flag CONTEXT_EXTENDED_REGISTERS猜成语一个人在跑.
  // The format and contexts are processor specific
ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} CONTEXT;
好了,线程就先讲这么多了。如果对进程和线一个人在看书猜成语程的内容感兴趣,可以到Intel的网站下载疯狂猜图一个人PDF格式的电子书《IA-32 Intel Architecture Software Developer’s Manual》,纸版的书也可以在这儿预定一个人一支笔猜成语(他们会免费邮寄给你)。通过这套书,你可以对CPU的结构一个人大肚子猜成语有一个清晰的认识。另外可以找几本讲疯狂猜成语一个人解Windows系统的书看看,不过这类的好书不多,最著名的是《Advance Windows》,不过也是偏向于实用,对系统结构的讲解不多。也是,要完全去了解一只虎一个人猜成语这部分的细节,太困难了,毕竟微软没有给我们一个人拿红旗猜成语提供这部分的源码。幸好,其实我们理解它大致一个人丢骨头猜成语的原理就足够用了。
2、多线程存猜成语一个人在跑在的问题
我们首先看一段多线程程序(该疯狂猜成语一个人跑程序可以在Code的MultiThreading中找到):
int g_i = 10;
//一个全局变量
DWORD WINAPI ThreadProc(LPVOID lpv)
g_i += 10;
std::cout &&&In the Thread & && ::GetCurrentThreadId()一个人一支笔猜成语一个人一支笔猜成语一只虎一个人猜成语疯狂猜图一个人猜成语一个人在跑一只虎一个人猜成语疯狂猜图一个人一个人在看书猜成语 && &,the first g_i is &
Sleep(5000); //睡眠
g_i += 10;
std::cout &&&In the Thread & && ::GetCurrentThreadId()一个人一支笔猜成语一个人一支笔猜成语一只虎一个人猜成语疯狂猜图一个人猜成语一个人在跑一只虎一个人猜成语疯狂猜图一个人一个人在看书猜成语 && &,the secend g_i is &
&& &!& && std::
int main(int argc, char* argv[])
DWORD threadID[2];
HANDLE hThreads[2];
for(int i = 0; i &= 1; i++ )
//创建两个线程
hThreads[i] = ::CreateThread(NULL,
ThreadProc,
&threadID[i]);
WaitForMultipleObjects(2一个人一支笔猜成语一个人大肚子猜成语,hThreads,TRUE,INFINITE);
//等待线程结束
for(i = 0; i &= 1; i++ )
::CloseHandle(hThreads[i]);
//关闭线程句柄
system(&pause&);
示例程序2-多一个人拿红旗猜成语线程程序
这段程序的本意是让一个人丢骨头猜成语全局变量累次加10,并打印出操作后的数值。但我们运行程序猜成语一个人在跑后的结果如下,可以看到程序的运疯狂猜成语一个人跑行结果非我们所愿。打印出的结果是一个人在看书猜成语一串乱序的文字。&
如何解决这个问题呢?我们需要利用疯狂猜图一个人同步机制来控制我们的多线程程序,现在我们使用临界一个人一支笔猜成语区来解决这个问题。代码如下:(在Code的MultiThreading中将进入临界区和离一个人大肚子猜成语开临界区的代码前的注释去掉就可以了)
int g_i = 10;
//一个全局变量
CRITICAL_SECTION
//一个临界区变量
DWORD WINAPI ThreadProc(LPVOID lpv)
EnterCriticalSection(&cs);
//进入临界区
g_i += 10;
std::cout & &
&In the Thread & & &
::GetCurrentThreadId()一个人一支笔猜成语一个人一支笔猜成语一只虎一个人猜成语疯狂猜图一个人猜成语一个人在跑一只虎一个人猜成语疯狂猜图一个人一个人在看书猜成语 & &
&,the first g_i is &
::LeaveCriticalSection(&cs);
Sleep(5000); //睡眠
EnterCriticalSection(&cs);
g_i += 10;
std::cout & &
&In the Thread & & &
::GetCurrentThreadId()一个人一支笔猜成语一个人一支笔猜成语一只虎一个人猜成语疯狂猜图一个人猜成语一个人在跑一只虎一个人猜成语疯狂猜图一个人一个人在看书猜成语 & &
&,the secend g_i is &
::LeaveCriticalSection(&cs);
int main(int argc, char* argv[])
DWORD threadID[2];
HANDLE hThreads[2];
InitializeCriticalSection(&cs);
for(int i = 0; i & = 1; i++ )
//创建两个线程
hThreads[i] = ::CreateThread(NULL,
    0,
    ThreadProc,
    NULL,
    0,
   疯狂猜图一个人 &threadID[i]);
WaitForMultipleObjects(2一个人一支笔猜成语一个人大肚子猜成语,hThreads,TRUE,INFINITE);
//等待线程结束
for(i = 0; i & = 1; i++ )
::CloseHandle(hThreads[i]);
//关闭线程句柄
system(&pause&);
再次运行,结果就是我们一只虎一个人猜成语所需要的了。&
如上所示我们通过在代码中加一个人拿红旗猜成语入EnterCriticalSection和LeaveCriticalSection来实现对数据的保护,如我们只在程序开头和结一个人丢骨头猜成语尾填加这两个函数的话,也不会太复杂,但是这样也就失去猜成语一个人在跑了多线程的意义。程序不会更快,反而会变慢。所以我们必须疯狂猜成语一个人跑在所有需要保护的地方,对我们的操作进行保护。程序如果庞大的话,这将是一个烦琐一个人在看书猜成语而枯燥的工作,而且很容易出错。如果是我们自己疯狂猜图一个人使用的类的话,我们可以选择一个人一支笔猜成语不使用多线程,但组件是提供一个人大肚子猜成语给别人用的。开发者无法阻止组件使用者在多疯狂猜成语一个人线程程序中使用自己提供的组件,这就要求组件必须一只虎一个人猜成语是多线程安全的。但并不是每个开发者一个人拿红旗猜成语都愿意做这样的工作,微软的COM API设计者为了一个人丢骨头猜成语平衡这个问题,就提出了套间的概念。&
注意:以上只是猜成语一个人在跑一个简单的例子,事实上多线程中需要保护的部分一般集中在全痉杩癫鲁捎镆桓鋈伺苤数据和静态数据之上,因为这样的数据每一个人在看书猜成语个进程只有一份,如上所示的g_i。(想对多线程程序疯狂猜图一个人有更深入的认识,可以找侯捷翻译的《Win32一个人一支笔猜成语多线程程序设计》看看,90年代出的书,到现在还畅销,足可以说明它一个人大肚子猜成语的价值)
二、套间所要疯狂猜成语一个人解决的问题   
从多线程的描述中,我们知道,套间所要解决的问题是帮助组件的开发者一只虎一个人猜成语在实现多线程下调用组件时候的同步问题。我们还是先看一一个人拿红旗猜成语段简短的程序。
我们首先使用ATL创建一个人丢骨头猜成语一个简单的组件程序,该程序有一猜成语一个人在跑个接口(ITestInterface1),该接口支持疯狂猜成语一个人跑一个方法TestFunc1。(该组件可以在附加的源码的“Apartment\TestComObject1”目录一个人在看书猜成语下找到)我们通过以下的程序调用该组件。(该程序可以在附加的源疯狂猜图一个人码的“Apartment\ErrorUseApartment”目录下找到)
#define _WIN32_WINNT 0x0400
#include &..\TestComObject1\TestComObject1疯狂猜成语一个人跑疯狂猜成语一个人疯狂猜成语一个人跑一个人大肚子猜成语_i一个人一支笔猜成语.c&
#include &..\TestComObject1\TestComObject1疯狂猜成语一个人跑疯狂猜成语一个人疯狂猜成语一个人跑一个人大肚子猜成语.h&
DWORD WINAPI ThreadProc(LPVOID lpv)
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if ( FAILED(hr) )
std::cout && &CoinitializeEx failed!& && std::
ITestInterface1 *pTest = NULL;
hr = ::CoCreateInstance(CLSID_TestInterface1疯狂猜成语一个人跑一个人一支笔猜成语猜成语一个人在跑疯狂猜图一个人一个人一支笔猜成语一只虎一个人猜成语,
CLSCTX_INPROC,
IID_ITestInterface1,
(void**)&pTest);
if ( FAILED(hr) )
std::cout && &CoCreateInstance疯狂猜图一个人疯狂猜成语一个人一个人在看书猜成语一个人大肚子猜成语疯狂猜成语一个人一个人丢骨头猜成语 failed!& && std::
hr = pTest-&TestFunc1();
if ( FAILED(hr) )
std::cout && &TestFunc1 failed!& && std::
pTest-&Release();
::CoUninitialize();
int main(int argc, char* argv[])
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if ( FAILED(hr) )
std::cout && &CoinitializeEx failed!& && std::
ITestInterface1 *pTest = NULL;
hr = ::CoCreateInstance(CLSID_TestInterface1疯狂猜成语一个人跑一个人一支笔猜成语猜成语一个人在跑疯狂猜图一个人一个人一支笔猜成语一只虎一个人猜成语,
CLSCTX_INPROC,
IID_ITestInterface1,
(void**)&pTest);
if ( FAILED(hr) )
std::cout && &CoCreateInstance疯狂猜图一个人疯狂猜成语一个人一个人在看书猜成语一个人大肚子猜成语疯狂猜成语一个人一个人丢骨头猜成语 failed!& && std::
DWORD threadID;
HANDLE hThreads
::CreateThread(NULL, //创建一个进程
ThreadProc,
//将pTest作为一个参一只虎一个人猜成语数传入新线程
&threadID);
hr = pTest-&TestFunc1();
if ( FAILED(hr) )
std::cout && &TestFunc1 failed!& && std::
::WaitForSingleObject(hThreads疯狂猜成语一个人跑一个人大肚子猜成语一个人丢骨头猜成语,INFINITE); //等待线程结束
::CloseHandle(hThreads);
//关闭线程句柄
pTest-&Release();
::CoUninitialize();
system(&pause&);
该段程序将main中一个人一支笔猜成语定义的ITestInterface1对象,通过指针传到了一个人大肚子猜成语新建的线程中。运行该段程序,结果如下,又是一串乱序的文字串。也就是说我们需要在TestComObject1中疯狂猜成语一个人对TestFunc1进行线程同步控制。但大多数人并一只虎一个人猜成语不想这样做,因为我们开发的组件大多数一个人拿红旗猜成语情况下并不会在多线程执行。但为了避免低概率事一个人丢骨头猜成语件发生后的不良后果,套间出场了。&
三、套间如何实猜成语一个人在跑现数据的同步
我们已经知道套间的目的疯狂猜成语一个人跑是用来实现数据的同步,那么套间如何来实现呢?如果我们能保证COM对象中一个人在看书猜成语的函数只能在该对象中的另一个函数执行完以后,才能开始执行(也就是说组件中疯狂猜图一个人的函数只能一个一个的执行),那么我们的问题一个人一支笔猜成语就可以解决了。是的,你可以发现,这样的话,就失去了多线程的优势;但套间的目的是保证一个人大肚子猜成语小概率下的线程安全,损耗一些性能,应该比出现逻疯狂猜成语一个人辑错误强点。&
那么又如何保证同一对象下的所有方法一只虎一个人猜成语都必须按顺序逐个执行呢?微软的COM API设计者们借用一个人拿红旗猜成语了Windows的消息机制。我们先来看一下一个人丢骨头猜成语windows的消息机制图。&
我们可以看到所有线程发出的猜成语一个人在跑消息都回首先放到消息队列中,然后在通过消息循环疯狂猜成语一个人跑分发到各自窗口去,而消息队列中的消息只能一一个人在看书猜成语个处理完后再处理另一个,借助消息机制,就可以实现COM的函疯狂猜图一个人数一个一个的执行,而不会同时运行。Windows的消息机制是通一个人一支笔猜成语过窗口来实现的,那么一个线程一个人大肚子猜成语要接收消息,也应该有一个窗口。 COM API的设计者在它们的API函数疯狂猜成语一个人中实现了一个隐藏的窗口。在我们一只虎一个人猜成语调用CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)的一个人拿红旗猜成语时候,会生成这个窗口。(如果你对softice等动态一个人丢骨头猜成语调试工具熟悉的话,可以通过跟踪源猜成语一个人在跑码来跟踪CoInitializeEx函数,可以发现它会调疯狂猜成语一个人跑用API函数CreateWindowEx)。该窗口是隐藏的,有了这个窗口,就可以支持消息机制,就有办法来实现对象一个人在看书猜成语中函数的逐一执行。这样当对象指针被传疯狂猜图一个人到其它线程的时候,从外部调用该对一个人一支笔猜成语象的方法的时候,就会先发一个一个人大肚子猜成语消息到原线程,而不再直接访问对象了。套间的原理大疯狂猜成语一个人致就是这样。我们再来看看COM一只虎一个人猜成语中的套间类型。
四、套间的类型
我们首先看看ATL为我们一个人拿红旗猜成语提供的线程类型:Single,Apartment,Both,Free。我们还是通过例子一个人丢骨头猜成语来说明它们的不同。我们仍然用我们使用刚猜成语一个人在跑才实现的TestComObject1来进行测试,先对它实现的唯一疯狂猜成语一个人跑方法进行一下说明。
STDMETHODIMP CTestInterface1::TestFunc1()
// TODO: Add your implementation code here
std::cout && &In the itestinferface1''s object, the thread''s id is & && ::GetCurrentThreadId()一个人一支笔猜成语一个人一支笔猜成语一只虎一个人猜成语疯狂猜图一个人猜成语一个人在跑一只虎一个人猜成语疯狂猜图一个人一个人在看书猜成语 && std::
return S_OK;
该方法非常简单,就是打印出该一个人一支笔猜成语方法运行时,所在的线程的ID号。如果在不同的线程中调一个人大肚子猜成语用同一个对象的时候,通过套间,发送消息,最终该对象只应该疯狂猜成语一个人在一个线程中运行,所以它的线程ID一只虎一个人猜成语号应该是相同的。我们将通过该ID值一个人拿红旗猜成语来验证套间的存在。
先来看我们的示例程序(在Code/Apartment/SingleApartment一个人丢骨头猜成语目录下可以找到该工程):
#define _WIN32_WINNT 0x0400
#include &..\TestComObject1\TestComObject1疯狂猜成语一个人跑疯狂猜成语一个人疯狂猜成语一个人跑一个人大肚子猜成语_i一个人一支笔猜成语.c&
#include &..\TestComObject1\TestComObject1疯狂猜成语一个人跑疯狂猜成语一个人疯狂猜成语一个人跑一个人大肚子猜成语.h&
DWORD WINAPI ThreadProc(LPVOID lpv)
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if ( FAILED(hr) )
std::cout && &CoinitializeEx failed!& && std::
ITestInterface1 *pTest = NULL;
hr = ::CoCreateInstance(CLSID_TestInterface1疯狂猜成语一个人跑一个人一支笔猜成语猜成语一个人在跑疯狂猜图一个人一个人一支笔猜成语一只虎一个人猜成语,
CLSCTX_INPROC,
IID_ITestInterface1,
(void**)&pTest);
if ( FAILED(hr) )
std::cout && &CoCreateInstance疯狂猜图一个人疯狂猜成语一个人一个人在看书猜成语一个人大肚子猜成语疯狂猜成语一个人一个人丢骨头猜成语 failed!& && std::
hr = pTest-&TestFunc1();
if ( FAILED(hr) )
std::cout && &TestFunc1 failed!& && std::
pTest-&Release();
::CoUninitialize();
int main(int argc, char* argv[])
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if ( FAILED(hr) )
std::cout && &CoinitializeEx failed!& && std::
ITestInterface1 *pTest = NULL;
hr = ::CoCreateInstance(CLSID_TestInterface1疯狂猜成语一个人跑一个人一支笔猜成语猜成语一个人在跑疯狂猜图一个人一个人一支笔猜成语一只虎一个人猜成语,
CLSCTX_INPROC,
IID_ITestInterface1,
(void**)&pTest);
if ( FAILED(hr) )
std::cout && &CoCreateInstance疯狂猜图一个人疯狂猜成语一个人一个人在看书猜成语一个人大肚子猜成语疯狂猜成语一个人一个人丢骨头猜成语 failed!& && std::
hr = pTest-&TestFunc1();
if ( FAILED(hr) )
std::cout && &TestFunc1 failed!& && std::
DWORD threadID;
HANDLE hThreads[1];
hThreads[0]
::CreateThread(NULL, //创建一个进程
ThreadProc,
(LPVOID)pTest,
//将pTest作为一个参一只虎一个人猜成语数传入新线程
&threadID);
::WaitForSingleObject(hThreads疯狂猜成语一个人跑一个人大肚子猜成语一个人丢骨头猜成语,INFINITE); //等待线程结束
::CloseHandle(hThreads);
//关闭线程句柄
pTest-&Release();
::CoUninitialize();
system(&pause&);
以下是运行猜成语一个人在跑结果:&
可以看到,在main中我们创建了疯狂猜成语一个人跑一个ITestInterface1接口对象,并调用TestFunc1,此处会输出一个一个人在看书猜成语线程ID――ThreadID1。之后主线程生疯狂猜图一个人成一个线程,在该线程中,我们会再次生成一个人一支笔猜成语一个ITestInterface1接口对象,此处再次一个人大肚子猜成语调用TestFunc1,可以看到输出了另疯狂猜成语一个人一个线程ID――ThreadID2。因为是不同的对象,所以它们的线一只虎一个人猜成语程ID号不同。(注意了,此处并没有跨一个人拿红旗猜成语线程调用对象,并不在套间的保护范围)
好了,我们该来看看Single一个人丢骨头猜成语类型的套间了。如果你和我一样懒,不想为此去写一猜成语一个人在跑个single类型的接口,那么打开你的注册表。
找到我们的接口ID,在InprocServer32项下,将ThreadingModel的值疯狂猜成语一个人跑改为Single,或者将该项删除(这一个人在看书猜成语样也代表是Single套间)。我们再来运行该程序,再看运行结果。&
当打印出一个疯狂猜图一个人线程ID的时候,程序就停止了。Why?刚开始,我也被搞的头晕脑胀。到MSDN中一个人一支笔猜成语查找WaitForSingleObject,原来WaitForSingleObject会破坏程一个人大肚子猜成语序中的消息机制,这样在创建的线程中,TestFunc1需要通过消疯狂猜成语一个人息机制来运行,消息机制破坏,就无法运行了。哎!还的再改程序。在查查《Win32多线一只虎一个人猜成语程程序设计》,原来在GUI中等待一个人拿红旗猜成语线程需要用MsgWaitForMultipleObjects。好的,我们需要重新一个人丢骨头猜成语写一个函数,专门用来实现消息同步。
DWORD ApartMentMsgWaitForMultipleObject(HANDLE一个人在看书猜成语一个人大肚子猜成语猜成语一个人在跑 *hHandle,DWORD dwWaitCout, DWORD dwMilliseconds)
BOOL bQuit = FALSE;
while(!bQuit)
rc = ::MsgWaitForMultipleObjects
dwWaitCout, // 需要等待的一个人在看书猜成语对象数量
hHandle, // 对象树组
//等待所有的对象
(DWORD)dwMilliseconds一个人大肚子猜成语一个人拿红旗猜成语疯狂猜图一个人,
// 等待的时间
(DWORD)(QS_ALLINPUT | QS_ALLPOSTMESSAGE) 一个人一支笔猜成语 // 事件类型  
//等待的事件激发
WAIT_OBJECT_0 )
bQuit = TRUE;
//其他windows消息
else if( rc == WAIT_OBJECT_0 + dwWaitCout )
while (PeekMessage(&msg一只虎一个人猜成语猜成语一个人在跑一个人大肚子猜成语, NULL, 0, 0, PM_REMOVE))
TranslateMessage (&msg);
DispatchMessage(&msg);
return dwR
该函数用来处一只虎一个人猜成语理消息的同步,也够麻烦的,还需要自己写这段程序。这段程序的意思是如一个人拿红旗猜成语果等待的事件被激发,那么设置bQuit为TURE,那么退出消息循环。如果接收到其一个人丢骨头猜成语它的消息的话,再分发出去。好了,把我们的程序猜成语一个人在跑再改一下:
// ::WaitForSingleObject(hThreads疯狂猜成语一个人跑一个人大肚子猜成语一个人丢骨头猜成语,INFINITE); //等待线程结束
ApartMentMsgWaitForMultipleObject(hThreads一个人在看书猜成语疯狂猜图一个人一个人在看书猜成语,1,INFINITE);
我们再来看一疯狂猜图一个人下运行结果。&
我们可以看到一个人一支笔猜成语两处调用TestFunc1,得到的线程ID是相同的。我们再通过VC的调试功能来一个人大肚子猜成语看看第二个TestFunc1的运行过程。我们在两个TesfFunc1调疯狂猜成语一个人用处设置断点,然后通过F11跟踪进TestFunc1一只虎一个人猜成语来看看它的调用过程。以下是在Main中一个人拿红旗猜成语的调用过程。
通过Call Stack,我们可以看到,此处是在main中一个人丢骨头猜成语直接调用的。我们再来看第猜成语一个人在跑二处调用:
我们可以看到TestFunc1的调用需要疯狂猜成语一个人跑通过一连串的API方法来实现。你感兴趣的话,可以通过反汇编的方一个人在看书猜成语法来跟踪一下这些API,看看它们具体疯狂猜图一个人实现了什么,这里我们可以看到这些一个人一支笔猜成语函数在dll中的大致位置,你可以使用W32DASM等反汇一个人大肚子猜成语编工具打开这些dll,大致研究一下这些函数。
好了,我们已经看到了疯狂猜成语一个人Single套间的作用。那么Single套间究竟是什么意思呢?一只虎一个人猜成语就是说每个被标志为Single的接口,在一个进程中只会一个人拿红旗猜成语存活在一个套间中。该套间就是进程创一个人丢骨头猜成语建的第一个套间。你可以将Main中与pTest猜成语一个人在跑相关的代码都去掉,只保疯狂猜成语一个人跑留CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)和线程一个人在看书猜成语的创建,再次运行该程序,可以发现创建线程中的TestFunc1疯狂猜图一个人仍然是通过消息来实现的。
好了看过了Single,我们还是在注册表中,将ThreadingModel改一个人一支笔猜成语为Apartment。通过修改注册表就可以一个人大肚子猜成语实现对套间类型的控制,证明了套间和我们的程疯狂猜成语一个人序本身没有什么关系,ATL的选项所做的作用也只一只虎一个人猜成语是通过它来添加注册表。套间只是对系一个人拿红旗猜成语统的一种提示,由COM API通过注册表信息一个人丢骨头猜成语来帮我们实现套间。
2、Apartment
在第二部分(套间猜成语一个人在跑所要解决的问题),我们曾经提供了一个不同疯狂猜成语一个人跑线程共享接口对象的方法,该方法是错误的(我们也可一个人在看书猜成语以通过程序阻止这种用法,稍候再叙)。此处我们提供一疯狂猜图一个人种正确的做法。以下代码在Apartment/Apartmenttest一个人一支笔猜成语下可以找到。
#define _WIN32_WINNT 0x0400
#include &..\TestComObject1\TestComObject1疯狂猜成语一个人跑疯狂猜成语一个人疯狂猜成语一个人跑一个人大肚子猜成语_i一个人一支笔猜成语.c&
#include &..\TestComObject1\TestComObject1疯狂猜成语一个人跑疯狂猜成语一个人疯狂猜成语一个人跑一个人大肚子猜成语.h&
DWORD WINAPI ThreadProc(LPVOID lpv)
//HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED)一个人一支笔猜成语一个人大肚子猜成语;
if ( FAILED(hr) )
std::cout && &CoinitializeEx failed!& && std::
IStream *pStream = (IStream*)
ITestInterface1 *pTest = NULL;
hr = ::CoGetInterfaceAndReleaseStream(pStream一个人一支笔猜成语一个人丢骨头猜成语,
IID_ITestInterface1,
(void**)&pTest);
if ( FAILED(hr) )
std::cout && &CoGetInterfaceAndReleaseStream疯狂猜成语一个人疯狂猜成语一个人跑 failed!& && std::
hr = pTest-&TestFunc1();
if ( FAILED(hr) )
std::cout && &TestFunc1 failed!& && std::
pTest-&Release();
::CoUninitialize();
DWORD ApartMentMsgWaitForMultipleObject(HANDLE一个人在看书猜成语一个人大肚子猜成语猜成语一个人在跑 *hHandle,DWORD dwWaitCout, DWORD dwMilliseconds)
BOOL bQuit = FALSE;
while(!bQuit)
rc = ::MsgWaitForMultipleObjects
dwWaitCout,    // 需要等待的一个人在看书猜成语对象数量
// 对象树组
//等待所有的对象
(DWORD)dwMilliseconds一个人大肚子猜成语一个人拿红旗猜成语疯狂猜图一个人,
// 等待的时间
(DWORD)(QS_ALLINPUT | QS_ALLPOSTMESSAGE) 一个人一支笔猜成语 // 事件类型  
WAIT_OBJECT_0 )
bQuit = TRUE;
else if( rc == WAIT_OBJECT_0 + dwWaitCout )
while (PeekMessage(&msg一只虎一个人猜成语猜成语一个人在跑一个人大肚子猜成语, NULL, 0, 0, PM_REMOVE))
  TranslateMessage (&msg);
  疯狂猜成语一个人跑DispatchMessage(&msg);
return dwR
int main(int argc, char* argv[])
//HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED)一个人一支笔猜成语一个人大肚子猜成语;
if ( FAILED(hr) )
std::cout && &CoinitializeEx failed!& && std::
ITestInterface1 *pTest = NULL;
hr = ::CoCreateInstance(CLSID_TestInterface1疯狂猜成语一个人跑一个人一支笔猜成语猜成语一个人在跑疯狂猜图一个人一个人一支笔猜成语一只虎一个人猜成语,
CLSCTX_INPROC,
IID_ITestInterface1,
(void**)&pTest);
if ( FAILED(hr) )
std::cout && &CoCreateInstance疯狂猜图一个人疯狂猜成语一个人一个人在看书猜成语一个人大肚子猜成语疯狂猜成语一个人一个人丢骨头猜成语 failed!& && std::
hr = pTest-&TestFunc1();
if ( FAILED(hr) )
std::cout && &TestFunc1 failed!& && std::
IStream *pStream = NULL;
hr = ::CoMarshalInterThreadInterfaceInStream(IID_ITestInterface1一只虎一个人猜成语一个人拿红旗猜成语,
&pStream);
if ( FAILED(hr) )
std::cout && &CoMarshalInterThreadInterfaceInStream一个人拿红旗猜成语一个人丢骨头猜成语 failed!& && std::
DWORD threadID;
HANDLE hThreads[1];
hThreads[0]
::CreateThread(NULL,
//创建一个进程
    0,
    ThreadProc,
   猜成语一个人在跑 (LPVOID)pStream,
//将pStream作为一个参疯狂猜成语一个人跑数传入新线程
    0,
   一个人在看书猜成语 &threadID);
ApartMentMsgWaitForMultipleObject(hThreads一个人在看书猜成语疯狂猜图一个人一个人在看书猜成语,1,INFINITE);
::CloseHandle(hThreads);
//关闭线程句柄
pTest-&Release();
::CoUninitialize();
system(&pause&);
我们通过CoGetInterfaceAndReleaseStream将main一个人拿红旗猜成语中的pTest变为pStream,然后将pStream作为参一个人丢骨头猜成语数传入到线程中,然后再通过CoGetInterfaceAndReleaseStream将猜成语一个人在跑pSteam变为接口指针。再来看看运行疯狂猜成语一个人跑的结果:
可以看到两次运行,线程ID是相同的。好的,我们接着改变注册表,再将Apartment一个人在看书猜成语变为Free。然后再将疯狂猜图一个人两处的HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);改一个人一支笔猜成语为HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED)一个人一支笔猜成语一个人大肚子猜成语。编译后再次执行该程序,再来看执行结果。
我们可以看到两个疯狂猜成语一个人线程的ID是不同的。你可以通过VC的Debug来看这一只虎一个人猜成语两组程序的TesFunc1的调用情况,在第二种情况下,创建的线程中不会通过一个人拿红旗猜成语消息机制来调用该函数。&
通过对比,我们可以知道一个人丢骨头猜成语所说的套间,就是通过消息机制来控制猜成语一个人在跑不同线程中对对象的调用。这样就不需要组件的实疯狂猜成语一个人跑现者来实现数据的同步。
上节的例子,已经为我们提示一个人在看书猜成语了我们Free套间,其实系统对我们疯狂猜图一个人的组件不做控制,这样就需要组件的开发者一个人一支笔猜成语对数据的同步做出控制。
所谓Both,就是说该对象既一个人大肚子猜成语可以运行在Apartment中,也可以运行疯狂猜成语一个人在Free套间中。该类型的前提是它应一只虎一个人猜成语该是Free类型的套间,也就是说组件自己一个人拿红旗猜成语实现了数据的同步。然后设置成Both类型。&
为什么需要Both类型的套间呢?想想假如一个人丢骨头猜成语我们在我们的组件中调用另一个组件,这样我们就需要在我们的组件中猜成语一个人在跑为所调用的组件来开辟一个套间。我们的套间疯狂猜成语一个人跑是一个Apartment,而调用的组件一个人在看书猜成语是Free类型的,这样这两个对象就必须存疯狂猜图一个人在于不同的两个套间中。而跨套间的调用,需要通过中间一个人一支笔猜成语代理来实现,这样必然会损失性能。但如果我们调用的一个人大肚子猜成语套间类型是Both的话,它就可以和我们的疯狂猜成语一个人组件同享一个套间,这样就可以提高效率。
五、缺省套间
继续我们的测试,首先在注册表中将我一只虎一个人猜成语们的接口类型改回Apartment。然后新建一一个人拿红旗猜成语个工程DefaultApartment。C++文件中的实一个人丢骨头猜成语现代码如下。
#define _WIN32_WINNT 0x0400
#include &..\TestComObject1\TestComObject1疯狂猜成语一个人跑疯狂猜成语一个人疯狂猜成语一个人跑一个人大肚子猜成语_i一个人一支笔猜成语.c&
#include &..\TestComObject1\TestComObject1疯狂猜成语一个人跑疯狂猜成语一个人疯狂猜成语一个人跑一个人大肚子猜成语.h&
DWORD WINAPI ThreadProc(LPVOID lpv)
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
//HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED)一个人一支笔猜成语一个人大肚子猜成语;
if ( FAILED(hr) )
std::cout && &CoinitializeEx failed!& && std::
IStream *pStream = (IStream*)
ITestInterface1 *pTest = NULL;
hr = ::CoGetInterfaceAndReleaseStream(pStream一个人一支笔猜成语一个人丢骨头猜成语,
IID_ITestInterface1,
(void**)&pTest);
if ( FAILED(hr) )
std::cout && &CoGetInterfaceAndReleaseStream疯狂猜成语一个人疯狂猜成语一个人跑 failed!& && std::
std::cout && &ThradProc''s threadid is & && ::GetCurrentThreadId()一个人一支笔猜成语一个人一支笔猜成语一只虎一个人猜成语疯狂猜图一个人猜成语一个人在跑一只虎一个人猜成语疯狂猜图一个人一个人在看书猜成语 && std:: //输出ThradProc一个人拿红旗猜成语的线程ID
hr = pTest-&TestFunc1();
if ( FAILED(hr) )
std::cout && &TestFunc1 failed!& && std::
pTest-&Release();
::CoUninitialize();
DWORD ApartMentMsgWaitForMultipleObject(HANDLE一个人在看书猜成语一个人大肚子猜成语猜成语一个人在跑 *hHandle,DWORD dwWaitCout, DWORD dwMilliseconds)
BOOL bQuit = FALSE;
while(!bQuit)
rc = ::MsgWaitForMultipleObjects
dwWaitCout,    // 需要等待的一个人在看书猜成语对象数量
// 对象树组
//等待所有的对象
(DWORD)dwMilliseconds一个人大肚子猜成语一个人拿红旗猜成语疯狂猜图一个人,
// 等待的时间
(DWORD)(QS_ALLINPUT | QS_ALLPOSTMESSAGE) 一个人一支笔猜成语 // 事件类型  
WAIT_OBJECT_0 )
bQuit = TRUE;
else if( rc == WAIT_OBJECT_0 + dwWaitCout )
while (PeekMessage(&msg一只虎一个人猜成语猜成语一个人在跑一个人大肚子猜成语, NULL, 0, 0, PM_REMOVE))
  TranslateMessage (&msg);
  疯狂猜成语一个人跑DispatchMessage(&msg);
return dwR
int main(int argc, char* argv[])
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
//HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED)一个人一支笔猜成语一个人大肚子猜成语;
if ( FAILED(hr) )
std::cout && &CoinitializeEx failed!& && std::
ITestInterface1 *pTest = NULL;
hr = ::CoCreateInstance(CLSID_TestInterface1疯狂猜成语一个人跑一个人一支笔猜成语猜成语一个人在跑疯狂猜图一个人一个人一支笔猜成语一只虎一个人猜成语,
CLSCTX_INPROC,
IID_ITestInterface1,
(void**)&pTest);
if ( FAILED(hr) )
std::cout && &CoCreateInstance疯狂猜图一个人疯狂猜成语一个人一个人在看书猜成语一个人大肚子猜成语疯狂猜成语一个人一个人丢骨头猜成语 failed!& && std::
std::cout && &main''s threadid is & && ::GetCurrentThreadId()一个人一支笔猜成语一个人一支笔猜成语一只虎一个人猜成语疯狂猜图一个人猜成语一个人在跑一只虎一个人猜成语疯狂猜图一个人一个人在看书猜成语 && std::
//打印main一个人大肚子猜成语的线程ID
hr = pTest-&TestFunc1();
if ( FAILED(hr) )
std::cout && &TestFunc1 failed!& && std::
IStream *pStream = NULL;
hr = ::CoMarshalInterThreadInterfaceInStream(IID_ITestInterface1一只虎一个人猜成语一个人拿红旗猜成语,
&pStream);
if ( FAILED(hr) )
std::cout && &CoMarshalInterThreadInterfaceInStream一个人拿红旗猜成语一个人丢骨头猜成语 failed!& && std::
DWORD threadID;
HANDLE hThreads[1];
hThreads[0] =
::CreateThread(NULL,
//创建一个进程
    0,
    ThreadProc,
   猜成语一个人在跑 (LPVOID)pStream,
//将pStream作为一个参疯狂猜成语一个人跑数传入新线程
    0,
   一个人在看书猜成语 &threadID);
ApartMentMsgWaitForMultipleObject(hThreads一个人在看书猜成语疯狂猜图一个人一个人在看书猜成语,1,INFINITE);
::CloseHandle(hThreads);
//关闭线程句柄
pTest-&Release();
::CoUninitialize();
system(&pause&);
此部分代码与我们测试一只虎一个人猜成语Apartment时的代码基本相同,只是新增了输出main和一个人拿红旗猜成语创建线程的ID的语句。好的,我们来运行程序,可以得到如下一个人丢骨头猜成语的结果:
我们可以看到main的线程ID猜成语一个人在跑和两个TestFunc1的线程ID相同。也就是说两个TestFunc1都是疯狂猜成语一个人跑在main的线程中运行的。&
将我们的程序做些变动,将一个人在看书猜成语CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)改疯狂猜图一个人为 CoInitializeEx(NULL, COINIT_MULTITHREADED)一个人一支笔猜成语一个人大肚子猜成语。然后接着运行程序。我们再来看运行的结果。
我们可以看到两个TestFunc1的一个人大肚子猜成语线程ID和main的不同了,和我们创建的疯狂猜成语一个人线程也不同。这是为什么呢?CoInitializeEx是一只虎一个人猜成语一个创建套间的过程,我们使一个人拿红旗猜成语用CoInitializeEx(NULL, COINIT_MULTITHREADED)一个人一支笔猜成语一个人大肚子猜成语后,没有为我们的组件猜成语一个人在跑创建合适的套间。这时候系统疯狂猜成语一个人跑(也就是COM API,这里应该是通过CoCreateInstance来实现的)就会帮一个人在看书猜成语我们将我们的接口对象放入缺省套间,该套间并不运行疯狂猜图一个人在当前的线程中。我们再次在Debug下一个人一支笔猜成语跟踪运行过程,可以发现在一个人大肚子猜成语main中调用TestFunc1,也需要通过众多的疯狂猜成语一个人API函数帮助完成,也就是说此处也是通一只虎一个人猜成语过消息机制来完成的,这样性能上肯一个人拿红旗猜成语定会有影响。
六、阻止接口指一个人丢骨头猜成语针的非法使用
在第二部分我们给出了一个通过直猜成语一个人在跑接传输接口指针到另外线程的例子,事实上这种方疯狂猜成语一个人跑法是错误的,但COM API并没有帮助我们一个人在看书猜成语阻止这样的错误。这个任务可以由疯狂猜图一个人我们自己来完成。
因为套间是和一个人一支笔猜成语线程相关的,Apartment类型的接口方法只应该运行在一一个人大肚子猜成语个套间中(其实这就是一个协议,并不是强制性的),那么我们可以通过线疯狂猜成语一个人程的相关性质来实现。
在线程中我们一只虎一个人猜成语可以通过Thread Local Storage(TLS)来保存一个人拿红旗猜成语线程的相关信息,同一函数运行在一个人丢骨头猜成语不同的线程中,那么它所拥有猜成语一个人在跑的TLS也不相同。
我们来动手改造疯狂猜成语一个人跑我们的类实现,将CTestferface1进一个人在看书猜成语行改造。
class ATL_NO_VTABLE CTestInterface1 :
public CComObjectRootEx,
public CComCoClass,
public IDispatchImpl
DWORD dwTlsI
CTestInterface1()
dwTlsIndex = TlsAlloc();
HLOCAL l =
LocalAlloc(LMEM_FIXED疯狂猜图一个人, 1);
TlsSetValue(dwTlsIndex一个人一支笔猜成语, l);  
我们先声明一个一个人大肚子猜成语私有成员变量dwTlsIndex,它用来存放TLS的索引值(一疯狂猜成语一个人个线程的TLS相当于一个数组,可以存放不同的数据)。再将构造函数中填一只虎一个人猜成语入保存数据的代码。此处只是简单的分配一个人拿红旗猜成语了一个字节的地址,并将该地址通过一个人丢骨头猜成语TlsSetValue保存到TLS中去。
然后再改造我猜成语一个人在跑们的TestFunc1函数。如下:
STDMETHODIMP CTestInterface1::TestFunc1()
// TODO: Add your implementation code here
LPVOID lpvData = TlsGetValue(dwTlsIndex);
if ( lpvData == NULL )
return RPC_E_WRONG_THREAD;
std::cout && &In the itestinferface1''s object, the thread''s id is & && ::GetCurrentThreadId()一个人一支笔猜成语一个人一支笔猜成语一只虎一个人猜成语疯狂猜图一个人猜成语一个人在跑一只虎一个人猜成语疯狂猜图一个人一个人在看书猜成语 && std::
return S_OK;
这边也很简单,就是简单的通过TlsGetValue去尝试得一个人大肚子猜成语到dwTlsIndex所标志的内容是否存在。如果不存在,那么就说明程序运行疯狂猜成语一个人在了不同的套间中。就会返一只虎一个人猜成语回RPC_E_WRONG_THREAD,这是COM设计一个人拿红旗猜成语者定义的宏,表示线程的非法使用。(由于我的懒惰,不再写新的COM了,只是简单的一个人丢骨头猜成语修改了TestComObject1,这部分新加的代猜成语一个人在跑码被我注释掉了,你如果想看这疯狂猜成语一个人跑部分的效果,去掉注释就一个人在看书猜成语可以了)
我们再运疯狂猜图一个人行ErrorUseApartment程序,发现TestFunc1已经无一个人一支笔猜成语法输出线程号,而是直接一个人大肚子猜成语返回RPC_E_WRONG_THREAD。再次运行疯狂猜成语一个人ApartmentTest程序,发现这样的处理一只虎一个人猜成语对它并没有影响。仍然正常运行。
六、什么是套间?
我们从外部表现上一个人拿红旗猜成语对套间进行了了解,而套间究竟是什么一个人丢骨头猜成语?潘爱民译的《Com 本质论》说:套猜成语一个人在跑间既不是进程,也不是线程,然而套间拥有进程疯狂猜成语一个人跑和线程的某些特性。我觉得,这句话翻译的不到位,总让人感觉套间似乎是和一个人在看书猜成语进程或者线程等同的东西。找来原文看看:An apartment is neither a
however, apartments share some of the properties of both。这里的share被疯狂猜图一个人译成了拥有,但我感觉此处翻译为使用一个人一支笔猜成语或者分享可能更贴切一些。不过原文事实上也很容一个人大肚子猜成语易给初学者带来误导。其实套间只是保存在线程中的一个数疯狂猜成语一个人据结构(还有一个隐藏着的窗口),借用该结构使套间和线一只虎一个人猜成语程之间建立起某种关系,通过该关系,使得COM API通过该信息可以建立一个人拿红旗猜成语不同套间中的调用机制。这部分涉及到列集,散集(我一个人丢骨头猜成语们调用CoMarshalInterThreadInterfaceInStream,CoGetInterfaceAndReleaseStream的过猜成语一个人在跑程)。在列集和散集过程中,COM API会帮我们建立一个不疯狂猜成语一个人跑同套间中对象通信机制,这部分涉及到了代理,存根和通道的内容。通过代理来发一个人在看书猜成语送调用信息,通过通道发送到存根,再通过存根调用实际的方法(其实那疯狂猜图一个人个隐藏的窗口就是为存根来服务的)。所做的这一切不过是为了实现不同一个人一支笔猜成语套间中可以通过消息来调用对象。你可以找《Com 本质论》来看看,这部分的内容比较繁杂,但我感觉比起一个人大肚子猜成语套间的概念,还是比较容易的。
具体实现套间,在线程的TLS究竟保存了什么信息呢疯狂猜成语一个人?罪恶的微软隐藏了这边部分内容,我们无法得到一只虎一个人猜成语这部分的材料。这可能也是套间理解起一个人拿红旗猜成语来如此困难的一个原因,套间呈现给我们的一个人丢骨头猜成语是一个抽象的概念。但理解其实际意义后,抽不抽象已经猜成语一个人在跑没什么关系,因为它所隐藏的不过是创建和使用套疯狂猜成语一个人跑间时候繁杂的调用其它API函数的过程,事实上并没有太一个人在看书猜成语多的神秘可言。对我们开发者来说,能明白套间的意义,已经足够了。
好了,稍微总结一下:套间是保存在疯狂猜图一个人线程的TLS中的一个数据结构,通过该结构可以帮助不同的套间之一个人一支笔猜成语间通过消息机制来实现函数的调用,以保证多线程环境下,数据的同步。
石康说:比尔.盖茨并不是什么天才,软件工作者充其量不一个人大肚子猜成语过是一个技术工作者,无法和科学工疯狂猜成语一个人作者同日而语。石康还说:如果给他一只虎一个人猜成语老人家足够的时间,他也可以写出一个人拿红旗猜成语一个操作系统。呵呵,大意好象如此,似乎是他老人家在《一个人丢骨头猜成语支离破碎》中的名言,现在记不太清楚了。刚开始觉得他猜成语一个人在跑老人家太狂了,不过仔细体会一下,确实如此。计算机的世界很少疯狂猜成语一个人跑有真正高深的东西,有些内容你不理解,肯定是你的某方一个人在看书猜成语面的基础不扎实。不理解接口,那是因为你疯狂猜图一个人的C++没学好;不理解套间,那是因为你不懂多线程;不懂多线程那是因一个人一支笔猜成语为你不懂CPU的结构。
技术革新在眼花一个人大肚子猜成语缭乱的进行的,.Net,Web services,到处闪现着新鲜的名词,似乎这个世界每疯狂猜成语一个人天都在变化的。但事实上,从286到386,从dos到图形一只虎一个人猜成语操作系统后,计算机再没有什一个人拿红旗猜成语么重大的革新。从我们开发者一个人丢骨头猜成语的角度来看,不过是开发工具的更新。但每次开发工具的更新猜成语一个人在跑都能使很多人兴奋异常,激动着下载安装疯狂猜成语一个人跑最新版本的工具,追逐着学习最一个人在看书猜成语新的开发语言。总觉的这样就不疯狂猜图一个人会被时代所抛弃,总以为开发工具会帮一个人一支笔猜成语着提升自己的价值。事实上呢?学会拖一个人大肚子猜成语拉创建窗口的人,可能根本不知道Windows疯狂猜成语一个人中有一个消息机制。开发十多年的人会把一个栈中生成一只虎一个人猜成语的对象的地址作为参数传给接收者。没有学会走的时候,不要去跑。我自己也在迷茫中一个人拿红旗猜成语探索着自己的路,现在有点明白老子一个人丢骨头猜成语所说的“企者不立,跨者不行”。
好了,废话就此打住吧猜成语一个人在跑!只是想告诉你,其实编程并没疯狂猜成语一个人跑有那么困难,如果有什么东西没明白,别着急,找基础的东西去看。学好COM也一样,看不懂的话,先把C++中的虚一个人在看书猜成语函数学明白,再去了解一下疯狂猜图一个人多线程的内容。其实也没那一个人一支笔猜成语么复杂!
有人说,COM过时了,我也不清楚COM的一个人大肚子猜成语将来会怎么样,但我觉得理解一个疯狂猜成语一个人东西总是有乐趣的。与你同勉。
最多还可以一只虎一个人猜成语输入100字
【VIP年会员一个人拿红旗猜成语制套餐】
【C/C++软件工程师实战一个人丢骨头猜成语能力集训大纲】
VC知识库发布了C/C++业猜成语一个人在跑界的“本草纲目”
【牛人都在千疯狂猜成语一个人跑人一号群! 加群三步走!!!】
第一步:请必须一个人在看书猜成语加VC知识库QQ: 为好友;
第二步:请必须关疯狂猜图一个人注本站微博:
第三步:申请加入群:.(必须将关注微博截一个人一支笔猜成语屏发到QQ方可通过!)
【最新2013:】
全部100% VC++源码提供: E-Form++全新一个人大肚子猜成语大型SCADA & HMI解决方案源码、CAD解决方疯狂猜成语一个人案源码、Gis解决方案源码 、电力石油化工仿真与图形建模解决方案一只虎一个人猜成语源码、大量其他高级制图VC++源码下载!
【 新视频发布】
o o o o o o o o o o
在VC环境中除了我们所常用的Dialog一个人拿红旗猜成语、Menu和Bitmap等标准资源类型之外,它还支持自定义一个人丢骨头猜成语资源类型(Custom Resource),我们自定义的资源类型猜成语一个人在跑能做些什么呢?呵呵,用处多多。...
在VC环境中除了我们所常用的Dialog一个人拿红旗猜成语、Menu和Bitmap等标准资源类型之外,它还支持自定义一个人丢骨头猜成语资源类型(Custom Resource),我们自定义的资源类型猜成语一个人在跑能做些什么呢?呵呵,用处多多。...
本文介绍了套接字一个人一支笔猜成语编程的基本知识。...
本站部分内容系根据指令自动收集于互联网,不代表本站赞成该内容或立场
Copyright & 2011 www.51yue.net Corporation, All Rights Reserved
Processed in 0.921 second(s), 4 queries,}

我要回帖

更多关于 疯狂猜成语之一个蛋 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信