В Delphi 2009 и Windows API есть способ обнаружить, что определенный фрагмент кода выполняется в контексте вторичного потока? В псевдокоде я бы хотел сказать:
procedure DoSomething;
begin
if InvokedBySecondaryThread then
DoIt_ThreadSafeWay
else
DoIt_RegularWay;
end;
Это для библиотеки журналов, которую я писал и использовал годами, и сейчас пытаюсь приспособиться к ситуации, когда одна процедура может быть вызвана из нескольких потоков. Мой "обычный путь" не безопасен. Я знаю, как сделать это потокобезопасным, но я бы хотел использовать этот метод только тогда, когда это действительно необходимо.
Пояснение (не обязательно чтение: -)
Это сводится к выбору между использованием SendMessage и PostMessage для отправки зарегистрированного сообщения нескольким получателям, таким как файл журнала, консоль или элемент управления VCL. Использование PostMessage означает, что сообщения не будут получены, пока выполняется длительная операция блокировки, что несколько противоречит цели ведения журнала, особенно когда используется для обозначения прогресса. Я полагаю, что мог бы защитить вызов SendMessage с критической секцией, но я бы предпочел сделать это только тогда, когда это действительно необходимо.
Я знаю о глобальном var IsMultiThread в system.pas, но это только скажет мне, что приложение запустило вторичные потоки. Это могут быть потоки, созданные сторонними библиотеками, и поэтому они никогда не получат доступ к «моему» коду, поэтому их существование не повлияет на мою логику регистрации.
Мне бы очень хотелось использовать один и тот же низкоуровневый код библиотеки независимо от того, вызывается ли он из одного или нескольких потоков. Например, было бы легко вызывать модифицированные, поточно-безопасные процедуры ведения журнала из вторичных потоков, но это дублировало бы большой код, и мне все равно пришлось бы запомнить , чтобы всегда делать правильные вещи.
@ Ливен: В настоящее время логика ведения журнала выглядит следующим образом, несколько упрощенно
Я хочу, чтобы регистрация данных была максимально безболезненной, с минимальным кодом установки и не беспокоясь об управлении временем жизни объекта, поэтому библиотека предоставляет только несколько перегруженных вспомогательных процедур, таких как
procedure Log( const msgText : string; level : TLogLevel = lvNotice ); overload;
procedure Log( const msgText : string; Args : array of const; level : TLogLevel = lvNotice ); overload;
etc, including specialized routines that log a StringList, a boolean, an Exception and so on
Практически все остальное происходит при реализации устройства. Все вспомогательные процедуры в конечном итоге вызывают
procedure _LogPostMessage( const msgText : string; level : TLogLevel );
который (а) проверяет, был ли инициализирован объект-диспетчер синглтона; (б) создает экземпляр объекта TLogMessagePacket (контейнер для текста сообщения, отметки времени и т. д.) и, наконец, (в) выполняет SendMessage или PostMessage для отправки «пакета» диспетчеру (который имеет дескриптор окна для его получения). ).
Затем существует группа классов, происходящих от абстрактного класса TLogReceiver. Один такой класс получает зарегистрированные сообщения и записывает их в файл, другой обновляет TMemo и т. Д. Я создаю экземпляры конкретных получателей, которые хочу использовать в проекте, и регистрирую их у диспетчера, которому они принадлежат с этого момента.
Когда диспетчер получает сообщение «пакет», он по очереди передает его каждому получателю, а затем освобождает его.
Так что я, вероятно, исправил рассмотренный выше способ мышления, поэтому я не совсем понимаю вашу идею, когда вы говорите код, передающий объект диспетчера в библиотеку журналов, должен выбирать один в зависимости от контекста потока, Диспетчер действительно главный движок библиотеки, и только один существует за один раз.