Quand dois-je appeler CoInitialize() dans ce scénario?
Je suis en train de construire un multi-fileté service windows application en Delphi XE2 qui utilise ADO composants de base de données pour se connecter à SQL Server. J'ai utilisé CoInitialize(nil);
beaucoup de fois avant de l'intérieur de threads, mais dans ce cas, j'ai une fonction qui, je n'en suis pas sûr à propos de.
Cette fonction est appelée TryConnect
qui tente de se connecter à une base de données avec une chaîne de connexion. Elle renvoie vrai ou faux sur la réussite de la connexion. Le problème est que cette fonction sera utilisée à la fois à l'intérieur et à l'extérieur de la principale thread de service, et ce sera la création de ses propres temporaire TADOConnection
composant, ce qui nécessite CoInitialize
...
Ma question est dois-je appeler CoInitialize
à l'intérieur de cette fonction? Si je le fais, et depuis le service de l'exécution de la procédure utilise CoInitialize
aussi, seront-ils interférer si j'ai appeler cette fonction dans le service? Le TryConnect
fonction est à l'intérieur d'un objet qui est créé à partir de la principale thread de service (mais sera finalement déplacé à son propre thread). J'ai besoin de savoir si l'appelant CoInitialize()
deux fois par le même thread (et CoUninitialize
) interfèrent - et comment gérer ce scénario correctement.
Voici le code ci-dessous...
//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;
Afin de clarifier ce qu'il est vraiment en train de faire, je pourrais avoir l'occasion de cette:
CoInitialize(nil);
try
CoInitialize(nil);
try
//Do some ADO work
finally
CoUninitialize;
end;
finally
CoUninitialize;
end;
CoInitialize()
signifie que vous avez STAs. COM doit être initialisé pour chaque thread et CoInitialize()
/CoUnitialize()
les appels doivent être équilibrés. Je ne sais pas comment cela fonctionne en Delphi, mais vous auriez probablement à maréchal des pointeurs entre les threads.OriginalL'auteur Jerry Dodge | 2012-02-15
Vous devez vous connecter pour publier un commentaire.
CoInitialize
doit être appelé dans chaque thread qui utilise COM, indépendamment de ce fil, elle est, ou si elle a un thread parent ou de l'enfant de threads. Si le thread utilise COM, il doit appelerCoInitialize
.La bonne réponse est "ça dépend". Puisque vous savez que le thread de service a appelé
CoInitialize
, siTryConnect
est appelé à partir de la thread de service, il ne sera pas besoin d'être rappelée. Si les autres threads qui pourrait l'appeler ont également appelé àCoInitialize
, il n'a pas besoin d'être appelé, comme la fonction est exécuté dans le thread appelant.La MSDN documentation traite spécifiquement de cette question (italiques ajoutés):
Donc la réponse est: Si vous n'êtes pas sûr, appelez
CoInitialize
. Le faire dans untry..finally
bloc, et d'appelerCoUnitialize
dans lefinally
, ou initialiser dans le constructeur et annuler l'initialisation dans le destructeur.CoInitialize
peut être appelé plus d'une fois, tant il est enveloppé dans untry
bloc et il convient enfin deCoUninitialize
après chaque.Oui, comme décrit dans le dernier paragraphe de ma réponse.
OriginalL'auteur Ken White
Votre service thread devrait vraiment pas être de faire des travaux. Il doit être utilisé exclusivement pour répondre aux appels de Gestionnaire des Services. Le OnExecute ou OnStart/OnStop du service de contrôle de l'instanciation et l'exécution d'un "MainWorkThread" que représente la fonctionnalité de votre service. Voir https://stackoverflow.com/a/5748495/11225 pour un exemple.
Le principal travail thread pourrait faire le travail réel et/ou la déléguer à d'autres threads. Chaque thread peut utiliser COM devrait avoir le CoInitialize/CoUninitialize appels et de la façon la plus simple d'y parvenir est de code en plus à l'extérieur essayer enfin de bloquer le thread (remplacée) méthode Execute.
TDBPool ou de toute autre classe à l'aide de COM ne doit pas se préoccuper avec la CoInitialize et CoUninitialize appels. Ces méthodes doivent être appelés dans chaque thread qui pourrait utiliser COM et une classe n'est pas et ne devrait pas savoir dans quel fil il sera exécuté.
OriginalL'auteur Marjan Venema