Scintilla 和线程安全

发布于 2024-08-23 17:23:59 字数 487 浏览 13 评论 0原文

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

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

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

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

I'm using the Scintilla edit control on Windows (Win32, C/C++) . The control is created in WndProc. I have a second thread, created with Boost.Thread, that act as a spell checker and marks with red squiggle incorrectly spelled words. Therefore, I have two threads altering the content of the Scintilla control.

At first, the program was crashing when editing text. So I researched Scintilla for thread safety. I found little information, but I manage to get this quote in the documentation:

direct calling will cause problems if
performed from a different thread to
the native thread of the Scintilla
window in which case
SendMessage(hSciWnd, SCI_*, wParam,
lParam) should be used to synchronize
with the window's thread.

Of course, I'm using direct calls, accordingly I change all calls in the spell check thread to SendMessage and now the program doesn't crash anymore.
Finally, and that's the question, have I solved the problem, or am I going to encounter other quirks with Scintilla and multithreads?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一袭水袖舞倾城 2024-08-30 17:23:59

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

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

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

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

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

You should generally access windows (HWNDs) in Windows only from the thread they were created in. Any message sent to the window will be performed in the thread that created it, that's why the crashes stopped happening when you replaced all direct calls to the Scintilla functions by sending messages. If you use SendMessage() in your spell check thread this will cause the following to happen:

  • the spell check thread will block
  • a context switch to the GUI thread will be performed
  • the message loop will process the message (but not necessarily immediately, messages in the queue will be handled in the order they were added, so the message will be handled only after all previously added messages have been handled)
  • a context switch to the spell check thread will be performed
  • the SendMessage() call returns the result

So you have indeed fixed the problem, but at a very high price. Every misspelt word will cause two thread context switches, and the spell checking will block for each misspelt word. This could actually be quite a long time, if any other messages that take long to handle were still queued up.

You should change the design of your program. Ideally both threads will be able to work independently, and this can be achieved by adding a thread-safe data structure that the spell check thread adds information about misspelt words to, and that the main thread retrieves the information from. Boost has lots of classes to help you out. By doing so you can continue to use the direct calls, since they will be performed in the context of the main thread. Performance should improve, as multiple words could be underlined in one go, causing only a single repaint of the control. If you use PostMessage() instead of SendMessage() the spell check thread will be able to continue its work independently of the main thread being ready to handle the message.

If you remember to never call any Scintilla code from secondary threads you will not encounter other quirks. And this is nothing specific to the Scintilla control, calling Windows API functions that do not use Windows messages internally would be problematic for any other control just as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文