views:

95

answers:

1

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?

A: 

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.

mghie