2016-11-07 5 views
0

Задача, с которой я сталкиваюсь, заключается в том, что я пишу службу WCF, которая по своей природе многопоточна для работы с библиотекой C, которую я знаю, не является потокобезопасной, и у меня нет возможности влияют на библиотеку, которую я звоню. Библиотека, которую я вызываю, имеет метод инициализации для настройки оборудования и установки обработчика обратного вызова.C# Force Unmanaged Resources To Be Released

Если я выполняю этот процесс в консольном приложении, он работает абсолютно нормально, поскольку он находится в одном потоке.

Чтобы преодолеть проблемы, я создал класс-помощник, который реализует IDisposable для настройки оборудования, совершает вызовы и, надеюсь, разорвется, как только он будет завершен.

Sample вспомогательный класс:

public class MyClass 
{ 
[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] 
    private static extern void Setup(ushort var_one, ushort var_two); 

    [DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] 
    private static extern int Initialise(int port_num, int short_timeout, int long_timeout, 
                TXN_CALLBACK callback); 

    [DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] 
    private static extern IntPtr GetDeviceStatus(); 

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
    public delegate void TXN_CALLBACK(int size, [MarshalAs(UnmanagedType.LPStr)] string the_data); 

    private int Setup(ushort var_one, ushort var_two); 
    { 
     Setup(var_one, var_two); 
     int foo= Initialise(0, shorttimeout, longtimeout, txn_callback); 
     return foo; 
    }  

    public MyStruct GetStatus() 
    { 

     Setup(0, 0); 
     return PtrToStruct<MyStruct>(GetDeviceStatus());    
    } 

    private static void txn_callback(int size, string the_data) 
    { 
     // Do something with the data 
    } 

    private static T PtrToStruct<T>(IntPtr ptr) 
    { 
     if (ptr == IntPtr.Zero) 
     { 
      // Invalid pointer returned 
      return default(T); 
     } 

     return Marshal.PtrToStructure<T>(ptr); 
    } 
} 

телефонный код (WCF службы):

using (MyClass class = new MyClass()) 
{ 
    return class.GetStatus(); 
} 

Я ушел из IDisposable код, как это было установлено в качестве одноразового использования шаблона по умолчанию, созданной визуальной студии , Как бы то ни было, каждый раз, когда я вызываю GetStatus после первого, он знает, что я уже вызывал его до того, как перезапустил приложение. Я бы хотел, чтобы он вел себя каждый раз, когда я называю это, как будто это был первый раз. Любые идеи, которые мне нужно включить в код удаления, чтобы полностью начать с нуля каждый раз, когда я создаю экземпляр моего помощника?

+1

Если DLL не является потокобезопасной, реализация шаблона удаления не поможет многому с возможностью внутреннего коррумпированного состояния. Вам нужно убедиться, что только один поток обращается к библиотеке либо путем создания другого процесса, либо с помощью взлома с несколькими переименованными dlls. –

+0

. Я пробовал обернуть все службы с помощью lock(), чтобы библиотека не вызывалась из нескольких потоков, однако кажется разумным к тому факту, что он уже использовался процессом раньше. –

ответ

1

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

Учитывая, что вы не можете изменить базовую библиотеку, вам либо нужно вызвать функции в родной DLL, чтобы восстановить ее в состояние по умолчанию, либо вам нужно будет выгрузить ее из памяти между каждым использованием. Я уверен, что прежний вариант невозможен на основе вашего вопроса. У вас есть несколько вариантов, либо использовать Windows API для динамической загрузки и выгрузки DLL: How to dynamically load and unload a native DLL file?

... или обернуть эту DLL в другой ехе вашего решения, так, на строительство, ваша служба будет запущена ехе , поговорите с ним с помощью любого количества средств (вы можете создать для этого еще один слой службы WCF, stdin/out, named pipes, что угодно) и закройте exe, когда закончите с ним.

Я склоняюсь к методу exe, чтобы убедиться, что DLL полностью изолирована и не имеет возможности повредить ваше обслуживание, плюс вы также можете создавать несколько экземпляров (для каждого экземпляра службы WCF), если вам нужно поддерживать несколько сессий. Кроме того, когда вы создаете каждый экземпляр exe, вы можете получить идентификатор процесса и отслеживать его для сбоев, что делает ваш сервис еще более надежным.