首页 > 解决方案 > 获取托管类型的指针或通过句柄释放事件

问题描述

我有一个我无法真正改变的程序机制:

我有一个struct上下文。

我使用上下文的指针,而不是struct对象本身,因为我必须将此上下文传递给非托管代码,并且非托管代码将只接受指针作为参数,以便稍后在回调时将其返回给我。

我需要对有关上下文的特定函数使用任何限制性方法,因此它只能同时调用一次。

因此,我会使用SemaphoreSlim,或者如果我不能使用它,那么我仍然会使用ManualResetEventorAutoResetEvent作为解决方法,在技术上阻止上下文的函数调用,直到非托管代码调用回调,这样我就可以释放锁。

因为我需要传递一个指向非托管代码的指针,所以我通过将其与 固定,然后通过 获取指针来将我的上下文转换struct为。Context*GCHandle.Alloc()GCHandle.AddrOfPinnedObject()

问题是在我的上下文structSemaphoreSlim,或者Manual/AutoResetEvent是托管类型,这使我无法获取它们或事件上下文的指针。

是否有任何解决方案可以固定这些托管对象并获取它们的指针,然后再将它们转换回对象?

例如:

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


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

我知道因为这不是一个值类型,所以不可能通过这种方式获取它的地址,但是还有其他解决方案吗?

或者,作为替代解决方案,我可以使用并将它们的Manual/AutoResetEvent句柄作为IntPtr,但我不知道如何仅通过拥有.WaitOne()Set()Handle

任何想法将不胜感激!

标签: c#pointersevents

解决方案


好的,我发现这确实有效,但我想知道是否有更好的解决方案:

    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");
    }

(我知道我不必转换IntPtrtovoid*然后再转换回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");
    }

即使它正在工作,我对这个解决方案也不满意。有更好的想法吗?


推荐阅读