Правильная методология, чтобы заставить потоки использовать центральное соединение с базой данных - PullRequest
2 голосов
/ 14 февраля 2012

Я создаю многопоточное сервисное приложение в Delphi XE2. Каждый поток служит своей цели помимо других. Основной служебный поток отвечает только за поддержание работы других потоков и сохранение файла журнала и т. Д. Каждый из этих потоков отчитывается перед основным служебным потоком через синхронизированные триггеры событий. Эти потоки создаются при запуске службы и уничтожаются при ее завершении.

Я бы хотел представить отдельный поток как централизованное соединение с базой данных, чтобы избежать необходимости создавать множество экземпляров TADOConnection. Мой сервисный код может вызывать стандартные функции, такие как UserListDataSet := DBThread.GetUserList(SomeUserListDataSet);, или было бы неплохо, если бы я мог отправлять прямые операторы SQL, такие как SomeDataSet := DBThread.Get(MySqlText);. Я также хотел бы избежать слишком большого числа случаев CoInitialize() и т. Д.

Потоки заданий должны будут использовать этот поток БД. Мне нужно выяснить, как «спросить» его об определенных данных, «дождаться» ответа и «получить» этот ответ обратно в потоке, который его запросил. Я уверен, что есть много подходов к этому, но мне нужно знать, какой из них лучше всего подходит для моего сценария. Сообщения Windows? События? Должен ли я иметь какую-то очередь? Должен ли он отправлять наборы данных или что-то еще? Есть ли что-то, что может сделать это? Мне нужно выяснить, как структурировать этот поток БД таким образом, чтобы его можно было повторно использовать из других потоков.

Структура выглядит так:

+ SvcThread
  + DBThread
    + TADOConnection
  + Thread1
  + Thread2
  + Thread3

Мне нужны потоки 1, 2 и 3 для отправки запросов в DBThread. Когда поток отправляет ему какой-либо запрос, он должен ждать, пока не получит ответ. Получив ответ, поток БД должен уведомить запрашивающий поток. Каждый из потоков может одновременно отправить запрос в этот поток БД.

Хороший учебник о том, как этого добиться, был бы идеальным - он просто должен подходить для моего сценария. Мне нужно знать не просто "как заставить два потока общаться друг с другом", а скорее "как заставить много потоков общаться с централизованным потоком базы данных". Эти потоки заданий создаются как дочерние элементы основного потока службы и не принадлежат потоку db. Поток базы данных не знает потоков заданий.

Ответы [ 3 ]

6 голосов
/ 14 февраля 2012

Обычно у вас есть очередь запросов, в которой хранятся все запросы.Поток вашей базы данных читает запрос из очереди, обрабатывает его, а затем вызывает процедуру обратного вызова, указанную инициатором запроса для обработки результата.Не уверен, как это соотносится с парадигмами Delphi, но основы должны быть такими же.

3 голосов
/ 14 февраля 2012

Я думаю, что использование пула соединений с БД подойдет для вашей проблемы.Это также позволит вам позже масштабировать приложение без необходимости создавать дополнительный поток БД, а затем управлять «балансировкой нагрузки» для этих потоков БД.

Поскольку вы упоминаете использование TADOConnection, пожалуйста, посмотритеэта реализация Cary Jensen http://cc.embarcadero.com/item/19975. Я успешно использую этот пул соединений с БД в нескольких приложениях.Я изменил его несколькими способами, включая использование INI-файла для контроля: максимальное количество соединений, время очистки, время ожидания и т. Д.

Кэри написал несколько статей, которые служат для него документацией.Один здесь http://edn.embarcadero.com/article/30027.

3 голосов
/ 14 февраля 2012

Есть ли у каких-либо "запрашивающих" потоков что-нибудь прибыльное, что они могли бы делать, ожидая ответа от базы данных? Если ответ «нет», поскольку я подозреваю, что это весьма вероятно, то, возможно, вы можете немного упростить вашу ситуацию, исключив необходимость в «потоке БД» полностью. Возможно, все потоки могут поочередно совместно использовать одно соединение с базой данных, используя объект взаимного исключения, чтобы заставить их «ждать своей очереди».

В этом сценарии было бы одно соединение с базой данных, и любой поток, который должен был использовать его, делал бы это. Но они должны были бы сначала получить объект мьютекса, удерживать его во время выполнения запросов к базе данных, а затем освободить мьютекс, чтобы следующий поток мог иметь свою очередь.

Если вы решите, что каким-то образом выгодно (или необходимо ...) выделить поток для управления соединением, то, возможно, вы могли бы достичь результата, используя (a) мьютекс для сериализации запросы, как и прежде; и (b) один объект события, чтобы сигнализировать потоку DB о том, что был отправлен новый запрос, и (c) другой объект события, чтобы сигнализировать, что запрос имеет было завершено.

В любом случае, если вы действительно определили, что потоки запрашивающей стороны не имеют ничего полезного, что они могли бы делать в то же время, у вас есть потоки, «просто спящие», пока не наступит их очередь. Затем они делают свое дело, прямо или косвенно. Здесь нет «очередей», нет сложных общих структур данных, просто потому что вы (скажем ...) определили, что в них нет необходимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...