2015-03-08 2 views
1

У меня многопоточное приложение, которое динамически загружает dlls (плагины). У меня есть потоки в DLL. Между хост-приложением и dll мой собственный SDK, который предназначен для обеспечения связи с плагинами dll (интерфейс библиотеки) и определения общих ресурсов между хост-приложением и dll (структурами данных и т. Д.).Использование таких же мьютексов в хост-приложении и dll

Хост-приложение создает объект mutex с помощью функции CreateMutex с помощью функции WinAPI и передает THandle созданного мьютекса для каждой загружаемой DLL. Когда поток в DLL меняет общие ресурсы, он использует мьютекс для его защиты. Как я уже сказал, я использую WinAPI.Windows unit для вызова CreateMutex и всех других связанных с mutex функций (Release и т. Д.).

Идея состоит в том, чтобы сделать кросс-платформу SDK, поэтому я собираюсь изменить SDK, и я хотел бы избавиться от единицы WinAPI.Windows и всех связанных с Windows материалов.

Я включил System.SyncObjs для использования класса TMutex. Теперь я не совсем уверен, как бы я узнал, что моя dll об этом классе. Один из вариантов - передать TMutex в мою DLL, но я думаю, что это не вариант, если я хочу сохранить типы данных primitve в своем SDK, потому что SDK должен быть доступен для других языков, таких как C++, C# ... и т. Д. Другая идея, которая пересекает мой ум должен использовать именованные мьютексы и просто передавать имя (строку) в DLL.

Согласно MSDN: Если мьютекс именованный мьютекс и объект существовал до этого вызова функции, возвращаемое значение является дескриптор существующего объекта, GetLastError возвращает ERROR_ALREADY_EXISTS, bInitialOwner игнорируется, и вызывающий поток не предоставил право собственности. Однако, если у вызывающего есть ограниченные права доступа, функция будет терпеть неудачу с ERROR_ACCESS_DENIED, и вызывающий должен использовать функцию OpenMutex.

Таким образом, я предполагаю, что DLL сможет использовать существующие именованные мьютексы (MyMutex), когда он вызовет TMutex.Create (..., 'MyMutex').

Я прав?

Благодарим за помощь и ваши предложения. Я очень ценю это!

+1

Вы не можете передать объект Delphi из exe в dll или наоборот. Вам нужно будет использовать типы платформ. Вместо того, чтобы передавать мьютексы, лучше использовать именованные мьютексы. –

+0

Вы * можете * передать объект Delphi, если оба exe и dll скомпилированы с включенными пакетами времени выполнения. Тем не менее, я бы придерживался только проходящей «THandle». Или лучше, «Pointer», и пусть exe/dll придумает это при необходимости. Написание кросс-платформенного кода не означает уничтожения устройства 'Windows'. Вы можете 'IFDEF', чтобы он использовался только на платформах Windows. Кросс-платформенный код в конечном итоге должен использовать API-интерфейсы, специфичные для платформы, они просто скрыты от общедоступных интерфейсов. –

+0

@Remy Вы можете сделать это только в том случае, если используете ту же самую версию компилятора. Недостаточно просто включить пакеты времени выполнения. Более того, вы можете передавать объекты, полностью определенные в пакетах. Вы не можете иметь типы, объявленные в exe или dll. –

ответ

1

Передача экземпляра класса между модулями, отличными от пакетов времени выполнения, не допускается. Это не действительная форма взаимодействия.

Поэтому я считаю, что самым чистым решением будет обернуть TMutex с интерфейсом. Вы можете передавать интерфейсы между любым типом модуля, даже с модулями, скомпилированными разными компиляторами.

Существует множество различных мьютексов, но, на мой взгляд, очевидным выбором было бы обернуть TMonitor. Интерфейс прост:

type 
    IMutex = interface 
    procedure Acquire; stdcall; 
    procedure Release; stdcall; 
    end; 

Совершенно безопасно передавать этот интерфейс между исполняемыми файлами и библиотеками DLL.

Реализация может выглядеть следующим образом:

type 
    TXplatMutex = class(TInterfacedObject, IMutex) 
    public 
    procedure Acquire; stdcall; 
    procedure Release; stdcall; 
    end; 

procedure TXplatMutex.Acquire; 
begin 
    TMonitor.Enter(Self); 
end; 

procedure TXplatMutex.Release; 
begin 
    TMonitor.Exit(Self); 
end; 

Вы можете обернуть любой мьютекс вам нравится в этом пути. Я выбрал TMonitor, потому что он поддерживается на всех платформах и является основным инструментом, используемым библиотечным кодом Embarcadero для синхронизации.

+0

Я уже использую интерфейсы в своем SDK, и я не думал использовать их для обмена объектами синхронизации с dll. Наверное, я слишком долго смотрю на ту же точку. Иногда лучше сделать шаг назад, чтобы увидеть решение. Благодаря! – Nix

2

мьютексы Windows, может быть «общим» в различных процессах (и в еще большей степени в EXE и DLL) - у вас есть два пути:

  1. Используйте именованный мьютекс.Используйте API OpenMutex(), чтобы получить дескриптор уже существующего мьютекса - вам нужно убедиться, что он вызван после CreateMutex() или он не найдет мьютекс для открытия.
  2. Использование DuplicateHandle() для безымянного мьютекса, она возвращает новый дескриптор действующего в целевом процессе (который может быть тем же самым, в случае DLL)

Часто API обертка в Delphi является слишком ограниченный для «сложных» сценариев. Использование напрямую API Windows даст вам полный доступ к базовым функциям, даже если Delphi не раскрывает их. Поверните, вы узнаете больше о том, как работает Windows, и это знание, которое вы всегда можете перерабатывать за пределами Delphi ... и вам не нужно использовать уродливые хаки для переноса чего-то, что не нужно обертывать интерфейсами или как ...

Если вам нужны кросс-платформенные возможности, напишите свои собственные обертки для реализации мьютекса OS - не полагайтесь на Delphi.

+1

@Luigi Asker уже вызывает 'CreateMutex'. У Asker уже есть решение для Windows, которое работает. Asker пытается выяснить, как сделать часть x-plat. Таким образом, весь ваш текст о том, что вам не нужно обертывать, кажется, пропустит этот момент. Тем не менее, ваш последний абзац. –

+0

Luigi спасибо. Да, как David siad У меня уже есть рабочее решение для Windows. Теперь я изменяю свой код как можно более кросс-платформенный. Мне нужно будет сделать некоторые обертки, особенно вокруг объектов синхронизации. Теперь я разделяю THandle var в моем приложении и dll, и теперь это работает, но я предполагаю, что это не тот случай, когда компилируется для MacOS. Так почему-то я должен избавиться от этой THandle (которая находится в моем SDK) var и сделать это по-другому, может быть, даже с различным apporach, чтобы сделать ее более универсальной. – Nix

+0

@ Хеффернан: проблема с низкоуровневыми системными объектами заключается в том, что их использование должным образом выходит за рамки простого переноса экземпляра Delphi вокруг них - вы должны быть уверены, что то, что получает другой поток или процесс, действительно * и * правильно * можно использовать , Вы должны следовать семантике ОС, чтобы создавать и передавать соответствующие «ручки». Если вы этого не сделаете, уверен, вы получите рабочий экземпляр Delphi, но это может быть оболочка неправильного объекта sytem. Например, установка и использование мьютексов POSIX немного отличается от Windows, вам необходимо убедиться, что каждый поток/процесс получает правильный мьютекс. – LDS

Смежные вопросы