Получение указателя управляемого типа ИЛИ выпуская событие дескриптором - PullRequest
0 голосов
/ 26 октября 2018

У меня есть программный механизм, который я не могу изменить:

У меня есть struct для контекстов.

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

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

Поэтому я бы использовал SemaphoreSlim, или, если я не могу это использовать, то явсе еще будет использовать ManualResetEvent или AutoResetEvent в качестве обходного пути, технически заблокировать вызов функции контекста, пока неуправляемый код не вызовет обратный вызов, поэтому я могу снять блокировку.

Поскольку мне нужно передать указатель нанеуправляемый код, который я преобразую в свой контекст struct в Context* с помощью , закрепление с помощью GCHandle.Alloc(), затем получение указателя с помощью GCHandle.AddrOfPinnedObject().

Проблема в моем контексте1026 * SemaphoreSlim или Manual/AutoResetEvent утраanaged type, который делает меня неспособным получить их, или событие указателя контекста.

Есть ли какое-либо решение закрепить эти управляемые объекты и получить их указатели, а затем привести их обратно к объекту?

Например:

SemaphoreSlim ss1 = new SemaphoreSlim(0);
SemaphoreSlim* pointerOfSemaphore = &ss1;


SemaphoreSlim ss2 = *pointerOfSemaphore;
ss2.Release();

Я знаю, потому что это не тип значения. Таким способом невозможно получить его адрес, но есть ли другое решение?

Или, какальтернативное решение: я могу использовать Manual/AutoResetEvent и получить их дескрипторы как IntPtr, но я не знаю, как выпустить их WaitOne() событие (сигнализирующее Set()) только при наличии Handle.

Любые идеи будут оценены по достоинству!

1 Ответ

0 голосов
/ 26 октября 2018

Хорошо, я понял, что это на самом деле работает, но мне интересно, есть ли какое-нибудь лучшее решение:

    unsafe
    {
        AutoResetEvent myEvent = new AutoResetEvent(false);
        AutoResetEvent coEvent = new AutoResetEvent(false);

        void* eventPtr = (void*)myEvent.Handle;

        Console.WriteLine("Before release");

        ThreadPool.QueueUserWorkItem(delegate
        {
            coEvent.Handle = (IntPtr)eventPtr;

            Thread.Sleep(3000);
            coEvent.Set();
        }, null);

        Console.WriteLine("Waiting for release");

        myEvent.WaitOne();

        Console.WriteLine("Event released");
    }

(я знаю, мне не нужно конвертировать IntPtr в void* и затем обратно к IntPtr, я сделал это специально, потому что я передаю его таким образом в неуправляемый код.)

С помощью некоторого «недокументированного» кода и с некоторой помощью здесь Я сделал обходной путь с SemaphoreSlim, и он действительно работает.

    unsafe
    {
        // Create semaphore
        SemaphoreSlim mySemaphore = new SemaphoreSlim(0);

        // Get size of semaphore
        SemaphoreSlim[] mySemArr = new SemaphoreSlim[2];
        TypedReference mySemRef1 = __makeref(mySemArr[0]);
        TypedReference mySemRef2 = __makeref(mySemArr[1]);
        int mySemaphoreSize = (int)((UInt64)(*((IntPtr*)&mySemRef2)) - (UInt64)(*((IntPtr*)&mySemRef1)));

        // Get pointer of semaphore
        TypedReference mySemaphoreTypeRef = __makeref(mySemaphore);
        IntPtr mySemaphorePtr = *(IntPtr*)(&mySemaphoreTypeRef);

        Console.WriteLine("Before release");

        // Start new thread
        ThreadPool.QueueUserWorkItem(delegate
        {
            // Convert IntPtr to byte "array"
            byte* sourcePtr = (byte*)mySemaphorePtr;

            // Create dummy semaphore
            SemaphoreSlim castedSemaphore = default(SemaphoreSlim);
            TypedReference castedSemaphoreTypeRef = __makeref(castedSemaphore);
            byte* castedSemaphorePtr = (byte*)*((IntPtr*)&castedSemaphoreTypeRef);

            // Copy mySemaphore to dummy
            for (int i = 0; i < mySemaphoreSize; ++i)
                castedSemaphorePtr[i] = sourcePtr[i];

            // Wait 3 seconds
            Thread.Sleep(3000);

            // Release semaphore
            castedSemaphore.Release();
        }, null);


        // Wait for release
        Console.WriteLine("Waiting for release");
        mySemaphore.Wait();

        // Released
        Console.WriteLine("Semaphore released");
    }

Упрощенная версия:

    unsafe
    {
        // Create semaphore
        SemaphoreSlim mySemaphore = new SemaphoreSlim(0);

        // Get pointer of semaphore
        TypedReference mySemaphoreTypeRef = __makeref(mySemaphore);
        byte* mySemaphorePtr = (byte*)*(IntPtr*)(&mySemaphoreTypeRef);

        Console.WriteLine("Before release");

        // Start new thread
        ThreadPool.QueueUserWorkItem(delegate
        {
            // Create dummy semaphore
            SemaphoreSlim castedSemaphore = default(SemaphoreSlim);
            TypedReference castedSemaphoreTypeRef = __makeref(castedSemaphore);
            byte* castedSemaphorePtr = (byte*)(*((IntPtr*)&castedSemaphoreTypeRef));                    

            // Copy mySemaphore to dummy
            for (int i = 0; i < sizeof(IntPtr); ++i)
                castedSemaphorePtr[i] = mySemaphorePtr[i];

            // Wait 3 seconds
            Thread.Sleep(3000);

            // Release semaphore
            castedSemaphore.Release();

        }, null);


        // Wait for release
        Console.WriteLine("Waiting for release");
        mySemaphore.Wait();

        // Released
        Console.WriteLine("Semaphore released");
    }

Несмотря на то, что он работает, я недоволен этим решением.Есть идеи получше?

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