1

我在 Windows (Win32, C/C++) 上使用 Scintilla 编辑控件。该控件是在 WndProc 中创建的。我有第二个线程,用 Boost.Thread 创建,它充当拼写检查器,并用红色波浪线标记拼写错误的单词。因此,我有两个线程更改 Scintilla 控件的内容。

起初,程序在编辑文本时崩溃。所以我研究了 Scintilla 的线程安全性。我发现的信息很少,但我设法在文档中得到了这个引用:

如果直接调用从不同线程执行到 Scintilla 窗口的本机线程会导致问题,在这种情况下,应使用 SendMessage(hSciWnd, SCI_*, wParam, lParam) 与窗口的线程同步。

当然,我使用的是直接调用,因此我将拼写检查线程中的所有调用更改为 SendMessage,现在程序不再崩溃。最后,这就是问题所在,我解决了这个问题,还是我会遇到 Scintilla 和多线程的其他怪癖?

4

1 回答 1

4

您通常应该HWND只从创建它们的线程访问 Windows 中的窗口(s)。发送到窗口的任何消息都将在创建它的线程中执行,这就是为什么当您替换对 Scintilla 的所有直接调用时崩溃停止发生的原因通过发送消息的功能。如果您SendMessage()在拼写检查线程中使用,这将导致以下情况发生:

  • 拼写检查线程将阻塞
  • 将执行到 GUI 线程的上下文切换
  • 消息循环将处理消息(但不一定立即处理,队列中的消息将按照添加的顺序处理,因此只有在处理完所有先前添加的消息后才会处理消息)
  • 将执行到拼写检查线程的上下文切换
  • SendMessage()调用返回结果

所以你确实解决了这个问题,但代价很高。每个拼写错误的单词都会导致两次线程上下文切换,并且拼写检查将阻止每个拼写错误的单词。如果任何其他需要很长时间处理的消息仍在排队,这实际上可能是相当长的时间。

您应该更改程序的设计。理想情况下,两个线程都能够独立工作,这可以通过添加一个线程安全的数据结构来实现,拼写检查线程将有关拼错单词的信息添加到该数据结构中,并且主线程从中检索信息。Boost 有很多课程可以帮助您。通过这样做,您可以继续使用直接调用,因为它们将在主线程的上下文中执行。性能应该会提高,因为可以一次性为多个单词加下划线,只导致一次重绘控件。如果您使用PostMessage()而不是SendMessage()拼写检查线程将能够独立于准备处理消息的主线程继续其工作。

如果您记得永远不要从辅助线程调用任何 Scintilla 代码,您将不会遇到其他怪癖。这并不是 Scintilla 控件所特有的,调用内部不使用 Windows 消息的 Windows API 函数对于任何其他控件也是有问题的。

于 2010-03-03T18:45:00.463 回答