Scintilla 和线程安全
我在 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
通常,您应该仅从创建窗口的线程访问 Windows 中的窗口 (
HWND
s)。发送到窗口的任何消息都将在创建它的线程中执行,这就是崩溃停止发生的原因您通过发送消息替换了对 Scintilla 函数的所有直接调用。如果您在拼写检查线程中使用SendMessage()
,这将导致发生以下情况:SendMessage()
调用返回结果因此您确实解决了问题,但代价非常高。每个拼写错误的单词都会导致两次线程上下文切换,并且每个拼写错误的单词都会阻止拼写检查。如果任何其他需要很长时间才能处理的消息仍在排队,这实际上可能会花费相当长的时间。
您应该更改程序的设计。理想情况下,两个线程都能够独立工作,这可以通过添加线程安全的数据结构来实现,拼写检查线程将有关拼写错误的单词的信息添加到该数据结构中,并且主线程从中检索信息。 Boost 有很多课程可以帮助你。通过这样做,您可以继续使用直接调用,因为它们将在主线程的上下文中执行。性能应该会提高,因为可以一次性为多个单词添加下划线,从而只导致控件的一次重绘。如果您使用
PostMessage()
而不是SendMessage()
,拼写检查线程将能够独立于主线程准备好处理消息而继续其工作。如果您记得永远不要从辅助线程调用任何 Scintilla 代码,您将不会遇到其他怪癖。这并不是 Scintilla 控件特有的,调用内部不使用 Windows 消息的 Windows API 函数对于任何其他控件来说也会出现问题。
You should generally access windows (
HWND
s) 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 useSendMessage()
in your spell check thread this will cause the following to happen:SendMessage()
call returns the resultSo 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 ofSendMessage()
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.