c# - 获取托管类型的指针或通过句柄释放事件
问题描述
我有一个我无法真正改变的程序机制:
我有一个struct
上下文。
我使用上下文的指针,而不是struct
对象本身,因为我必须将此上下文传递给非托管代码,并且非托管代码将只接受指针作为参数,以便稍后在回调时将其返回给我。
我需要对有关上下文的特定函数使用任何限制性方法,因此它只能同时调用一次。
因此,我会使用SemaphoreSlim
,或者如果我不能使用它,那么我仍然会使用ManualResetEvent
orAutoResetEvent
作为解决方法,在技术上阻止上下文的函数调用,直到非托管代码调用回调,这样我就可以释放锁。
因为我需要传递一个指向非托管代码的指针,所以我通过将其与 固定,然后通过 获取指针来将我的上下文转换struct
为。Context*
GCHandle.Alloc()
GCHandle.AddrOfPinnedObject()
问题是在我的上下文struct
中SemaphoreSlim
,或者Manual/AutoResetEvent
是托管类型,这使我无法获取它们或事件上下文的指针。
是否有任何解决方案可以固定这些托管对象并获取它们的指针,然后再将它们转换回对象?
例如:
SemaphoreSlim ss1 = new SemaphoreSlim(0);
SemaphoreSlim* pointerOfSemaphore = &ss1;
SemaphoreSlim ss2 = *pointerOfSemaphore;
ss2.Release();
我知道因为这不是一个值类型,所以不可能通过这种方式获取它的地址,但是还有其他解决方案吗?
或者,作为替代解决方案,我可以使用并将它们的Manual/AutoResetEvent
句柄作为IntPtr
,但我不知道如何仅通过拥有.WaitOne()
Set()
Handle
任何想法将不胜感激!
解决方案
好的,我发现这确实有效,但我想知道是否有更好的解决方案:
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
tovoid*
然后再转换回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");
}
即使它正在工作,我对这个解决方案也不满意。有更好的想法吗?
推荐阅读
- javascript - 使用纯 JavaScript 屏蔽名字和姓氏
- ruby-on-rails - 如何跳过 CSV 中不是 Rails 的“标题行”的第一行?
- python - 如何构建一个独立的 Scrapy Spider?
- java - 使用 Java Spring Boot 创建 MySQL JSON 列
- chromium - 使用 Puppeteer 移除 kiosk 模式 Chromium 中的灰条
- loops - 谷歌表格循环/迭代仅可见的表格
- javascript - 单击更改颜色
- c++ - 如何在考虑对象切片的同时通过传入单个 Base 对象来打印数组中的对象?
- python - AttributeError: 'bool' 对象没有属性
- paho - pythonanywher 上的 paho-mqtt 身份验证错误