多线程调用COM组件的体会(CoInitialize)
来源:互联网 发布:淘宝给予警告会降权吗 编辑:程序博客网 时间:2024/06/06 07:25
调用任何COM组件之前,你必须首先初始化COM套件环境,即调用CoInitialize或CoInitializeEx。COM套件环境在线程的生存周期内有效,线程退出前需要调用CoUninitialize释放COM套件。
所谓COM套件,实际上是微软为了方便大家理解而起的一个名字,不过个人认为改名词很难理解。COM套件只指COM组件运行时的环境,其中包括COM组件的数据、变量、线程调度方式。
COM套件分为两种模式,单线程套件(STA)和多线程套件(MTA)。不要单从字面上理解,例如:STA并非只能用于单线程的程序,多线程程序依然可以使用。下面列出两种套件模式的区别。
套件类型
说明
性能兼容性
常见错误STA单线程套间,一个进程内所有COM组件都运行在主STA中,主STA就是第一个调用CoInitialize函数的线程。
也就是说,即使你拥有多线程程序,但在不通线程同时操作COM组件的时候,COM组件会通过Windows消息、Event同步对象之类的机制把调用转换到主STA执行,而主STA通常对应应用程序的主线程。这样对STA套件内的任何COM组件操作,实际上是单线程操作,COM组件不必关心线程同步的细节,因为根本没有必要进行线程同步。
低
如果一个COM组件是MTA的,可以安全的运行与STA套件中。
由于STA套件所有的COM组件代码都运行于主STA(第一个调用CoInitialize函数的线程),如果你的主线程没有调用CoInitialize,那么第一个调用CoInitialize的工作线程就会成为主STA,而工作线程随时可能中止,这种情况下,一旦工作线程中止主STA也就不复存在了,因此你需要在主线程中调用CoInitialize初始化主STA,即使主线程不使用任何COM组件。
MTA多线程套间,所有COM组件都运行在本线程的MTA套件中。
这是就会出现多个线程同时执行某个COM调用,COM组件的开发者必须预料并处理这种并发访问带来的内存竞争读写混乱。COM组件开发者通常会应用临界区、互斥量、信号灯之类的常规线程同步方法。而调用者,不需要担心COM组件是否会因为多线程挂掉。
高
如果一个COM组件是STA的,被错误的运行与MTA套件会引发各种奇怪的错误。
把STA的COM组件运行于MTA套件中会引发错误。
这就会引出一个问题,到底我该使用STA还是MTA呢,答案很简单问该COM组件的开发者,或者看他的说明文档,他们会告诉你。
STA套件的初始化方式(两种方式等效):
1,CoInitialize(nil);
2,CoInitializeEx(nil,COINIT_APARTMENTTHREADED);
MTA套间的初始化方式:
1,CoInitializeEx(nil,COINIT_MULTITHREADED);
附上一个多线程中,工作线程使用STA套件,但是主线程没有初始化主STA,引发的怪异错误的反面教材代码。
01
program
STATest;
02
03
04
{$APPTYPE CONSOLE}
05
06
uses
07
Windows,
08
Variants,
09
ComObj,
10
Classes,
11
SysUtils,
12
ActiveX;
13
14
type
15
TScriptThread=
class
(TThread)
16
public
17
procedure
Execute; override;
18
end
;
19
{ TScriptThread }
20
21
var
22
ThreadTotal:
Integer
;
23
ThreadCount:
Integer
;
24
25
procedure
TScriptThread
.
Execute;
26
var
FVBScriptEngine:Variant;
27
begin
28
try
29
30
//初始化工作线程的STA
31
CoInitialize(
nil
);
32
try
33
FVBScriptEngine:=CreateOleObject(
'ScriptControl'
);
34
FVBScriptEngine
.
AllowUI:=
False
;
35
FVBScriptEngine
.
Timeout:=
500
;
36
FVBScriptEngine
.
Language:=
'VBScript'
;
37
finally
38
InterlockedDecrement(ThreadCount);
39
CoUninitialize;
40
end
;
41
except
42
on
E:Exception
do
43
Writeln
(E
.
Message);
44
end
;
45
end
;
46
47
begin
48
49
//主线程部分
50
51
52
53
//初始化主STA,删掉下面一行的注释即可让程序稳定运行。
54
55
//CoInitialize(nil);
56
57
58
ThreadCount:=
0
;
59
ThreadTotal:=
0
;
60
try
61
while
True
do
begin
62
63
//保持工作线程始终不超过100
64
while
ThreadCount>=
100
do
;
65
Inc(ThreadTotal);
66
With
TScriptThread
.
Create(
True
)
do
begin
67
InterlockedIncrement(ThreadCount);
68
FreeOnTerminate:=
True
;
69
Start;
70
end
;
71
Writeln
(ThreadTotal);
72
end
;
73
except
74
on
E:Exception
do
75
Writeln
(E
.
Message);
76
end
;
77
Readln(Input);
78
end
.
- 多线程调用COM组件的体会(CoInitialize)
- 多线程调用COM组件的体会(CoInitialize)
- 多线程调用com组件的体会 转
- COM库调用时的初始化:CoInitialize
- COM调用的时候需要先调用CoInitialize函数
- COM 经验的八个教训(1):总是调用 CoInitialize(Ex)
- [Delphi-码农]Delphi 多线程 “尚未调用CoInitialize错误”的解决方法
- 多线程调用COM组件,使用CoInitializeEx()
- 多线程中对COM的初始化CoInitialize应该注意的问题
- 调用COM组件的方法
- Jeff Prosise com经验 总是调用 CoInitialize(Ex)
- COM组件的多线程测试-Single模型(附录)
- COM组件的多线程测试-Apartment模型(附录)
- COM组件开发(四)——VC++调用COM组件的方法
- Qt-不调用CoInitialize-实现SDL多线程运行
- vc中调用Com组件的方法详解(转)
- C#调用C++类(以COM组件的形式)
- C#通过COM组件调用C++的代码(转载)
- JAVA [ TCP/IP ]
- 简单的触发器
- App Store 审核指南(中文版)
- ORA-01078: failure in processing system parameters
- MapReduce技术的初步了解与学习
- 多线程调用COM组件的体会(CoInitialize)
- Oracle SQL 插入特殊字符
- 多线程中操作 webBrowser 出错
- Spring 事务处理
- 浮动代码,兼容各种浏览器
- C64x+ iUniversal Codec Creation - from memcpy to Canny Edge Detector
- SVN Server 权限精细控制
- 使用ProGuard合并多个jar文件
- 搜索利器