CRITICAL_SECTION in c#
本文关键字:in SECTION CRITICAL | 更新日期: 2023-09-27 17:50:35
全部。我需要在c#代码中使用winapi关键部分。
首先,我导入函数:
[StructLayout(LayoutKind.Sequential)]
public struct CRITICAL_SECTION { public int dummy; }
// INIT CRITICAL SECTION
[DllImport("kernel32.dll")]
static extern bool InitializeCriticalSectionAndSpinCount(ref CRITICAL_SECTION
lpCriticalSection, uint dwSpinCount);
// DELETE CRITICAL SECTION
[DllImport("kernel32.dll")]
static extern void DeleteCriticalSection(ref CRITICAL_SECTION
lpCriticalSection);
// ENTER CRITICAL SECTION
[DllImport("kernel32.dll")]
static extern void EnterCriticalSection(ref CRITICAL_SECTION
lpCriticalSection);
// LEAVE CRITICAL SECTION
[DllImport("kernel32.dll")]
static extern void LeaveCriticalSection(ref CRITICAL_SECTION
lpCriticalSection);
通过这种方式,我尝试使用关键部分:
static void Main(string[] args)
{
GenerateArray();
InvokeThread invokeThread = () =>
{
WaitForSingleObject(ghSemaphore, 0);
EnterCriticalSection(ref CriticalSection); // critical section
int[] array = new int[ARRAY_SIZE_PER_THREAD];
int baseI = thread * ARRAY_SIZE_PER_THREAD;
for (int i = 0; i < ARRAY_SIZE_PER_THREAD; ++i)
{
array[i] = gList[baseI + i];
}
LeaveCriticalSection(ref CriticalSection); // critical section
ReleaseSemaphore(ghSemaphore, 1, IntPtr.Zero);
return 0;
};
ghSemaphore = CreateSemaphore(ref seqAttr, THREADS_NUMBER, THREADS_NUMBER, "");
InitializeCriticalSectionAndSpinCount(ref CriticalSection, 0);
IntPtr threadPtr = Marshal.GetFunctionPointerForDelegate(invokeThread);
IntPtr[] handlers = new IntPtr[THREADS_NUMBER];
for (int i = 0; i < THREADS_NUMBER; ++i)
{
int handle = CreateThread(IntPtr.Zero, 0, threadPtr, IntPtr.Zero, 0, 0);
handlers[i] = new IntPtr(handle);
}
WaitForMultipleObjects(THREADS_NUMBER, handlers, true, Infinite);
DeleteCriticalSection(ref CriticalSection); // delete critical section
}
}
但在下一行gList包含错误的值。如果我不使用关键部分,每件事都是好的。
for (int i = 0; i < ARRAY_SIZE_PER_THREAD; ++i)
{
array[i] = gList[baseI + i];
}
哪里可能有问题?
您对CRITICAL_SECTION
结构体的定义是错误的。在Windows中,标头大约有24个字节,但您的标头只有4个。
此外,你根本不做new CRITICAL_SECTION
。如果您需要它,InitializeCriticalSection
会设置数据,但不会分配。
我也同意使用来自.net的关键部分API似乎是一个糟糕的设计选择。如果必须这样做,那么我会考虑编写一个C++/CLI混合模式包装器。这样就可以直接包含windows头文件。
但是,p/invoke代码中有一个相当明显的缺陷。这是CRITICAL_SECTION
结构体的声明。您已经声明它包含一个整数值。但原生CCD_ 5比它大。在x86上它是24字节长,在x64上它是40字节长。您不需要声明任何字段,因为从您的角度来看,它只是一个不透明的内存块。
如果我是你,我会摆脱CRITICAL_SECTION
。我会将所有的ref CRITICAL_SECTION
参数更改为IntPtr
。我会使用Marshal.AllocHGlobal(40)
创建一个足够大的内存块来保存关键部分的数据。
例如:
[DllImport("kernel32.dll")]
static extern bool InitializeCriticalSectionAndSpinCount(
IntPtr lpCriticalSection,
uint dwSpinCount
);
等等。