1

Windows (Win32、C/C++) で Scintilla エディット コントロールを使用しています。コントロールは WndProc で作成されます。Boost.Thread で作成された 2 番目のスレッドがあります。これはスペル チェッカーとして機能し、スペルが間違っている単語を赤い波線でマークします。したがって、Scintilla コントロールの内容を変更する 2 つのスレッドがあります。

最初は、テキストの編集中にプログラムがクラッシュしていました。そこで、スレッドセーフについて Scintilla を調査しました。情報はほとんど見つかりませんでしたが、ドキュメントでこの引用を取得することができました:

別のスレッドから Scintilla ウィンドウのネイティブ スレッドに対して直接呼び出しを実行すると問題が発生します。この場合、SendMessage(hSciWnd, SCI_*, wParam, lParam) を使用してウィンドウのスレッドと同期する必要があります。

もちろん、私は直接呼び出しを使用しているので、スペル チェック スレッド内のすべての呼び出しを SendMessage に変更すると、プログラムがクラッシュしなくなりました。最後に、それが問題です。私は問題を解決しましたか、それとも Scintilla とマルチスレッドで他の癖に遭遇するのでしょうか?

4

1 に答える 1

4

通常、Windows のウィンドウ ( s) には、それらが作成されたスレッドからのみアクセスする必要がありますHWND。ウィンドウに送信されたメッセージは、それを作成したスレッドで実行されます。そのため、Scintilla へのすべての直接呼び出しを置き換えたときにクラッシュが発生しなくなりました。メッセージを送信することによって機能します。スペル チェック スレッドでを使用SendMessage()すると、次のことが起こります。

  • スペル チェック スレッドがブロックされます
  • GUIスレッドへのコンテキスト切り替えが実行されます
  • メッセージ ループはメッセージを処理します (ただし、必ずしもすぐに処理されるとは限りません。キュー内のメッセージは追加された順序で処理されるため、以前に追加されたすべてのメッセージが処理された後にのみメッセージが処理されます)。
  • スペル チェック スレッドへのコンテキスト スイッチが実行されます
  • SendMessage()呼び出しは結果を返します

それで、あなたは確かに問題を解決しましたが、非常に高い代償を払いました. スペルミスのある単語ごとに 2 つのスレッド コンテキスト スイッチが発生し、スペル チェックはスペルミスのある単語ごとにブロックされます。処理に時間がかかる他のメッセージがまだキューに入れられている場合、これは実際にはかなり長い時間になる可能性があります。

プログラムの設計を変更する必要があります。両方のスレッドが独立して動作できることが理想的です。これは、スペル チェック スレッドがスペルミスの単語に関する情報を追加し、メイン スレッドがそこから情報を取得するスレッド セーフなデータ構造を追加することで実現できます。Boostには、あなたを助けるためのクラスがたくさんあります。そうすることで、メインスレッドのコンテキストで実行されるため、直接呼び出しを引き続き使用できます。一度に複数の単語に下線が引かれ、コントロールの再描画が 1 回だけになるため、パフォーマンスが向上するはずです。PostMessage()スペル チェック スレッドの代わりに使用するSendMessage()と、メイン スレッドがメッセージを処理する準備ができているかどうかに関係なく、作業を続行できます。

セカンダリ スレッドから Scintilla コードを呼び出さないことを覚えておけば、他の癖に遭遇することはありません。これは Scintilla コントロールに固有のものではありません。内部で Windows メッセージを使用しない Windows API 関数を呼び出すと、他のコントロールでも同様に問題が発生します。

于 2010-03-03T18:45:00.463 に答える