multithreading - 在这种情况下什么时候需要调用 CoInitialize() ?

标签 multithreading delphi activex ado delphi-xe2

我正在 Delphi XE2 中构建一个多线程 Windows 服务应用程序,它使用 ADO 数据库组件连接到 SQL Server。我用过CoInitialize(nil);在内部线程之前很多次,但在这种情况下,我有一个我不确定的函数。

该函数名为 TryConnect它尝试使用给定的连接字符串连接到数据库。连接成功时返回 true 或 false。问题是这个函数将在主服务线程内部和外部使用,并且它将创建自己的临时TADOConnection组件,需要 CoInitialize ...

我的问题是我需要打电话CoInitialize也在这个函数里面吗?如果我这样做,并且由于服务的执行过程使用 CoInitialize另外,如果我从服务内调用此函数,他们会干扰吗? TryConnect函数位于从主服务线程创建的对象内部(但最终将移动到其自己的线程)。我需要知道是否调用CoInitialize()来自同一线程的两次(和 CoUninitialize )会干扰 - 以及如何正确处理这种情况。

下面是代码...

//This is the service app's execute procedure
procedure TJDRMSvr.ServiceExecute(Sender: TService);
begin
  try
    CoInitialize(nil);
    Startup;
    try
      while not Terminated do begin
        DoSomeWork;
        ServiceThread.ProcessRequests(False);
      end;
    finally
      Cleanup;
      CoUninitialize;
    end;
  except
    on e: exception do begin
      PostLog('EXCEPTION in Execute: '+e.Message);
    end;
  end;
end;

//TryConnect might be called from same service thread and another thread
function TDBPool.TryConnect(const AConnStr: String): Bool;
var
  DB: TADOConnection; //Do I need CoInitialize in this function?
begin
  Result:= False;
  DB:= TADOConnection.Create(nil);
  try
    DB.LoginPrompt:= False;
    DB.ConnectionString:= AConnStr;
    try
      DB.Connected:= True;
      Result:= True;
    except
      on e: exception do begin
      end;
    end;
    DB.Connected:= False;
  finally
    DB.Free;
  end;
end;

因此,为了澄清它真正在做什么,我可能会遇到这样的情况:

CoInitialize(nil);
try
  CoInitialize(nil);
  try
    //Do some ADO work
  finally
    CoUninitialize;
  end;
finally
  CoUninitialize;
end;

最佳答案

CoInitialize 必须在使用 COM 的每个线程中调用,无论它是什么线程,或者是否有父线程或子线程。如果线程使用 COM,则必须调用 CoInitialize

这里的正确答案是“视情况而定”。由于您知道服务线程已调用 CoInitialize,因此如果从服务线程调用 TryConnect,则无需再次调用。如果可以调用它的其他线程也调用了CoInitialize,则不需要调用它,因为该函数将在调用线程下运行。

MSDN文档专门解决了这个问题(强调):

Typically, the COM library is initialized on a thread only once. Subsequent calls to CoInitialize or CoInitializeEx on the same thread will succeed, as long as they do not attempt to change the concurrency model, but will return S_FALSE. To close the COM library gracefully, each successful call to CoInitialize or CoInitializeEx, including those that return S_FALSE, must be balanced by a corresponding call to CoUninitialize. However, the first thread in the application that calls CoInitialize with 0 (or CoInitializeEx with COINIT_APARTMENTTHREADED) must be the last thread to call CoUninitialize. Otherwise, subsequent calls to CoInitialize on the STA will fail and the application will not work.

所以答案是:如果您不确定,请调用CoInitialize。在 try..finally block 中执行此操作,并在 finally 中调用 CoUnitialize,或者在构造函数中初始化并在析构函数中取消初始化。

关于multithreading - 在这种情况下什么时候需要调用 CoInitialize() ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9286600/

相关文章:

multithreading - 多线程二进制差异工具?

.net - 线程和核心

java - ThreadLocal 与新局部变量相比的真正优势

delphi - 如何使用 MSBuild 和 Delphi XE2 进行构建

c++ - com: pDispatch->invoke() 时参数数量无效

c++ - 多线程程序中的核心转储:basic_string::_S_construct null 无效

macos - Delphi 和 OSX - 使用 App Bundle 部署 Unix 可执行文件

sql - 在 Delphi 中显示 SQL 查询的进度

excel - Matlab - ActiveX 移动 Excel 工作表

c++ - 如何将数据文件加载到自动 Excel 工作表文档?