Access Violation Exception EnterCriticalSection WinAPI C#

huangapple go评论59阅读模式
英文:

Access Violation Exception EnterCriticalSection WinAPI C#

问题

我不明白是什么导致了这个错误。

[DllImport("kernel32.dll")]
static extern void EnterCriticalSection(ref IntPtr lpCriticalSection);

[DllImport("kernel32.dll")]
static extern void LeaveCriticalSection(ref IntPtr lpCriticalSection);

public Form1()
{
   InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
    unsafe
    {
        try
        {
            IntPtr criticalSection = new IntPtr();
            EnterCriticalSection(ref criticalSection);
            LeaveCriticalSection(ref criticalSection);
        }
        catch (AccessViolationException exception)
        {
            Console.WriteLine(exception.Message);
        }
    }
}

我尝试在Visual Studio中将生成类型从Any CPU更改为x86,但没有产生结果。

英文:

I don't understand what is causing this error

[DllImport("kernel32.dll")]
static extern void EnterCriticalSection(ref IntPtr lpCriticalSection);

[DllImport("kernel32.dll")]
static extern void LeaveCriticalSection(ref IntPtr lpCriticalSection);

public Form1()
{
   InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
    unsafe
    {
        try
        {
            IntPtr criticalSection = new IntPtr();
            EnterCriticalSection(ref criticalSection);
            LeaveCriticalSection(ref criticalSection);
        }
        catch (AccessViolationException exception)
        {
            Console.WriteLine(exception.Message);
        }
    }
}

I tried in Visual Studio to change the build type from Any CPU to x86, but it didn't bring results.

答案1

得分: 0

EnterCriticalSection() 需要接收一个已经使用 InitializeCriticalSection()InitializeCriticalSectionAndSpinCount() 初始化过的 CRITICAL_SECTION 结构体的指针作为参数。

但是,您却传递了一个未初始化的 IntPtr 的引用,它并没有指向有意义的位置。因此,当 EnterCriticalSection() 尝试访问一个不存在的结构体时,程序会崩溃。

正确的代码应该类似于以下内容:

[StructLayout(LayoutKind.Sequential)]
public struct CRITICAL_SECTION
{
    public IntPtr DebugInfo;
    public int LockCount;
    public int RecursionCount;
    public IntPtr OwningThread;
    public IntPtr LockSemaphore;
    public UIntPtr SpinCount;
}

[DllImport("kernel32.dll")]
static extern void InitializeCriticalSection(ref CRITICAL_SECTION lpCriticalSection);

[DllImport("kernel32.dll")]
static extern void DeleteCriticalSection(ref CRITICAL_SECTION lpCriticalSection);

[DllImport("kernel32.dll")]
static extern void EnterCriticalSection(ref CRITICAL_SECTION lpCriticalSection);

[DllImport("kernel32.dll")]
static extern void LeaveCriticalSection(ref CRITICAL_SECTION lpCriticalSection);

public Form1()
{
   InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
    unsafe
    {
        try
        {
            CRITICAL_SECTION criticalSection = new CRITICAL_SECTION();
            InitializeCriticalSection(ref criticalSection);
            EnterCriticalSection(ref criticalSection);
            LeaveCriticalSection(ref criticalSection);
            DeleteCriticalSection(ref criticalSection);
        }
        catch (AccessViolationException exception)
        {
            Console.WriteLine(exception.Message);
        }
    }
}

然而,在C#中,您实际上不需要使用 CRITICAL_SECTION,可以使用 lock 语句 或者类似 System.Threading.Monitor同步原语

英文:

EnterCriticalSection() expects to be given a pointer to a CRITICAL_SECTION struct that has been initialized with either InitializeCriticalSection() or InitializeCriticalSectionAndSpinCount().

But instead, you are giving it a reference to an uninitialized IntPtr that doesn't point anywhere meaningful. Hence the crash when EnterCriticalSection() tries to access a struct that doesn't exist.

The correct code should look more like this:

[StructLayout(LayoutKind.Sequential)]
public struct CRITICAL_SECTION
{
    public IntPtr DebugInfo;
    public int LockCount;
    public int RecursionCount;
    public IntPtr OwningThread;
    public IntPtr LockSemaphore;
    public UIntPtr SpinCount;
}

[DllImport("kernel32.dll")]
static extern void InitializeCriticalSection(ref CRITICAL_SECTION lpCriticalSection);

[DllImport("kernel32.dll")]
static extern void DeleteCriticalSection(ref CRITICAL_SECTION lpCriticalSection);

[DllImport("kernel32.dll")]
static extern void EnterCriticalSection(ref CRITICAL_SECTION lpCriticalSection);

[DllImport("kernel32.dll")]
static extern void LeaveCriticalSection(ref CRITICAL_SECTION lpCriticalSection);

public Form1()
{
   InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
    unsafe
    {
        try
        {
            CRITICAL_SECTION criticalSection = new CRITICAL_SECTION();
            InitializeCriticalSection(ref criticalSection);
            EnterCriticalSection(ref criticalSection);
            LeaveCriticalSection(ref criticalSection);
            DeleteCriticalSection(ref criticalSection);
        }
        catch (AccessViolationException exception)
        {
            Console.WriteLine(exception.Message);
        }
    }
}

However, you really don't need to use CRITICAL_SECTION in C#, use the lock statement instead, or a synchronization primitive like System.Threading.Monitor.

huangapple
  • 本文由 发表于 2023年6月19日 01:50:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76501866.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定