All. I need to use winapi critical section in c# code.
First of all, I import functions:
[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);
In this way I try to use critical section:
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
}
}
But at next line gList containes wrong values. And every thing is good, if I don't use critical section.
for (int i = 0; i < ARRAY_SIZE_PER_THREAD; ++i)
{
array[i] = gList[baseI + i];
}
Where could be a problem?
Your definition of the
CRITICAL_SECTION
struct is wrong. In the Windows headers is has 24 bytes or so, but yours has only 4.Also, you don't do
new CRITICAL_SECTION
anywere. And you need it,InitializeCriticalSection
sets the data, but don't allocate it.I also agree that using the critical section API from .net seems like a bad design choice. If you must then I'd contemplate writing a C++/CLI mixed-mode wrapper. That way you can include the windows header files directly.
However, there is a rather obvious flaw in your p/invoke code. That's the declaration of the
CRITICAL_SECTION
struct. You've declared it as holding a single integer value. But the nativestruct
is bigger than that. On x86 it is 24 bytes long, and on x64 it is 40 bytes long. You don't need to declare any of the fields since from your perspective it's just an opaque block of memory.If I were you I would get rid of
CRITICAL_SECTION
. I would change all theref CRITICAL_SECTION
parameters toIntPtr
. And I would useMarshal.AllocHGlobal(40)
to create a large enough block of memory to hold the critical section data.For example:
and so on.