Access Violation Exception EnterCriticalSection WinAPI C#

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

Access Violation Exception EnterCriticalSection WinAPI C#

问题

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

  1. [DllImport("kernel32.dll")]
  2. static extern void EnterCriticalSection(ref IntPtr lpCriticalSection);
  3. [DllImport("kernel32.dll")]
  4. static extern void LeaveCriticalSection(ref IntPtr lpCriticalSection);
  5. public Form1()
  6. {
  7. InitializeComponent();
  8. }
  9. private void button1_Click(object sender, EventArgs e)
  10. {
  11. unsafe
  12. {
  13. try
  14. {
  15. IntPtr criticalSection = new IntPtr();
  16. EnterCriticalSection(ref criticalSection);
  17. LeaveCriticalSection(ref criticalSection);
  18. }
  19. catch (AccessViolationException exception)
  20. {
  21. Console.WriteLine(exception.Message);
  22. }
  23. }
  24. }

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

英文:

I don't understand what is causing this error

  1. [DllImport("kernel32.dll")]
  2. static extern void EnterCriticalSection(ref IntPtr lpCriticalSection);
  3. [DllImport("kernel32.dll")]
  4. static extern void LeaveCriticalSection(ref IntPtr lpCriticalSection);
  5. public Form1()
  6. {
  7. InitializeComponent();
  8. }
  9. private void button1_Click(object sender, EventArgs e)
  10. {
  11. unsafe
  12. {
  13. try
  14. {
  15. IntPtr criticalSection = new IntPtr();
  16. EnterCriticalSection(ref criticalSection);
  17. LeaveCriticalSection(ref criticalSection);
  18. }
  19. catch (AccessViolationException exception)
  20. {
  21. Console.WriteLine(exception.Message);
  22. }
  23. }
  24. }

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() 尝试访问一个不存在的结构体时,程序会崩溃。

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

  1. [StructLayout(LayoutKind.Sequential)]
  2. public struct CRITICAL_SECTION
  3. {
  4. public IntPtr DebugInfo;
  5. public int LockCount;
  6. public int RecursionCount;
  7. public IntPtr OwningThread;
  8. public IntPtr LockSemaphore;
  9. public UIntPtr SpinCount;
  10. }
  11. [DllImport("kernel32.dll")]
  12. static extern void InitializeCriticalSection(ref CRITICAL_SECTION lpCriticalSection);
  13. [DllImport("kernel32.dll")]
  14. static extern void DeleteCriticalSection(ref CRITICAL_SECTION lpCriticalSection);
  15. [DllImport("kernel32.dll")]
  16. static extern void EnterCriticalSection(ref CRITICAL_SECTION lpCriticalSection);
  17. [DllImport("kernel32.dll")]
  18. static extern void LeaveCriticalSection(ref CRITICAL_SECTION lpCriticalSection);
  19. public Form1()
  20. {
  21. InitializeComponent();
  22. }
  23. private void button1_Click(object sender, EventArgs e)
  24. {
  25. unsafe
  26. {
  27. try
  28. {
  29. CRITICAL_SECTION criticalSection = new CRITICAL_SECTION();
  30. InitializeCriticalSection(ref criticalSection);
  31. EnterCriticalSection(ref criticalSection);
  32. LeaveCriticalSection(ref criticalSection);
  33. DeleteCriticalSection(ref criticalSection);
  34. }
  35. catch (AccessViolationException exception)
  36. {
  37. Console.WriteLine(exception.Message);
  38. }
  39. }
  40. }

然而,在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:

  1. [StructLayout(LayoutKind.Sequential)]
  2. public struct CRITICAL_SECTION
  3. {
  4. public IntPtr DebugInfo;
  5. public int LockCount;
  6. public int RecursionCount;
  7. public IntPtr OwningThread;
  8. public IntPtr LockSemaphore;
  9. public UIntPtr SpinCount;
  10. }
  11. [DllImport("kernel32.dll")]
  12. static extern void InitializeCriticalSection(ref CRITICAL_SECTION lpCriticalSection);
  13. [DllImport("kernel32.dll")]
  14. static extern void DeleteCriticalSection(ref CRITICAL_SECTION lpCriticalSection);
  15. [DllImport("kernel32.dll")]
  16. static extern void EnterCriticalSection(ref CRITICAL_SECTION lpCriticalSection);
  17. [DllImport("kernel32.dll")]
  18. static extern void LeaveCriticalSection(ref CRITICAL_SECTION lpCriticalSection);
  19. public Form1()
  20. {
  21. InitializeComponent();
  22. }
  23. private void button1_Click(object sender, EventArgs e)
  24. {
  25. unsafe
  26. {
  27. try
  28. {
  29. CRITICAL_SECTION criticalSection = new CRITICAL_SECTION();
  30. InitializeCriticalSection(ref criticalSection);
  31. EnterCriticalSection(ref criticalSection);
  32. LeaveCriticalSection(ref criticalSection);
  33. DeleteCriticalSection(ref criticalSection);
  34. }
  35. catch (AccessViolationException exception)
  36. {
  37. Console.WriteLine(exception.Message);
  38. }
  39. }
  40. }

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:

确定