Hi all !
I am working on the ThreadSearch plugin and I have a problem with wxWidgets multi threading management.
Pecan, I know you advised me to avoid using graphical widgets in worker thread but I'd like to understand better that point of the wxWidgets framework.
My worker thread uses a cbStyledTextControl.
I found in wxWidgets documentation on wxMutexGuiEnter() :
This function must be called when any thread other than the main GUI thread wants to get access to the GUI library.
My worker thread uses the control in this way:
wxMutexGuiEnter();
FindInFile(*control, m_FilePaths[i], searchFlags);
wxMutexGuiLeave();
During the search, I can edit text, use contextual menu, use my Message tab ThreadSearch panel scrollbars but as soon as I enter the event table with a button click for example, both threads freeze, the worker one on a wxMutexGuiEnter() call.
Event handler code:
void ThreadSearchView::OnBtnSearchClick(wxCommandEvent &event)
{
// User clicked on Search/Cancel
if ( m_pFindThread != NULL )
{
StopThread();
}
else
{
// We start the thread search
cbFindReplaceData findData;
m_ThreadSearchPlugin.GetFindData(findData);
findData.findText = m_pCboSearchExpr->GetValue();
ThreadedSearch(findData);
}
event.Skip();
}
I do not use wxMutexGuiEnter because I am in the main thread for event handling (do I ?).
Nevertheless I tried with it and it does not work better.
I am using SVN 3811 on Win XP SP2 with gcc 3.4.5.
Does anyone have any idea on my problem ?
Thanks,
Dje
wxMutexGuiEnter();
FindInFile(*control, m_FilePaths[i], searchFlags);
wxMutexGuiLeave();
It is not a good idea to do that. The main thread also uses the same mutex before it does anything (look at evtloopcmn.cpp), so if the FinInFile operation is long enough you will hang C::B.
I strongly recommend that you will separate the search logic from the GUI and like TDragon suggested, once you have a result or partial results send an event to update the search result pane to the main thread.
Eran
Hi dje!,
I recently developed a search thread that supports the following:
- match case
- match whole word
- regular expression
- file extensions
- events and easy interface with the main thread
Source code (5 sources + 1 sample):
http://www.eistware.com/st/SearchThread.zip (http://www.eistware.com/st/SearchThread.zip)
The code was built and tested on windows using VS20005, so no makefile is provided, but you should be able to complie and run it
easily.
A brief usage:
#include "search_thread.h"
// to use the search thread, we first need to start it ..
//----------------------------------------------------------
// Initialisation
//----------------------------------------------------------
// The search thread is singleton object so there is ohly one instance of it.
SearchThreadST::Get()->Start();
//--------------------------------------------------------------
// Starting new search
//--------------------------------------------------------------
// to perform a search, we create a SearchData object
// and set it with information provided by the user
SearchData data;
data.SetFindString(wxT("something_to_search")); // the find string
data.SetMatchCase(true); // is search case sensetive?
data.SetMatchWholeWord(true); // match whole word?, see also: SetWordChars() function
data.SetRootDir(true); // our search will start here
data.SetRegularExpression(false); // use regular expression?
data.SetExtensions(wxT("*.cpp;*.h;*.hpp;*.hxx")); // look at these file types
SearchThreadST::Get()->SetNotifyWindow( this ); // all events will be fired to 'this'
SearchThreadST::Get()->PerformSearch( data ); // do the search
//-----------------------------------------------------------------------
// Stopping running search
//-----------------------------------------------------------------------
SearchThreadST::Get()->StopSearch();
//------------------------------------------------------------------------
// process results:
//------------------------------------------------------------------------
// SearchThread fires three events:
// wxEVT_SEARCH_THREAD_MATCHFOUND - a match was found
// wxEVT_SEARCH_THREAD_SEARCHEND - search ended
// wxEVT_SEARCH_THREAD_SEARCHCANCELED - search cancelled by user
// in your code, you need to define 3 event handlers:
// Note: that the events will be sent to the NotifyWindow set earlier
//---------------------------------------------------------------------
EVT_COMMAND(wxID_ANY, wxEVT_SEARCH_THREAD_MATCHFOUND, Frame::OnSearchThread)
EVT_COMMAND(wxID_ANY, wxEVT_SEARCH_THREAD_SEARCHCANCELED, Frame::OnSearchThread)
EVT_COMMAND(wxID_ANY, wxEVT_SEARCH_THREAD_SEARCHEND, Frame::OnSearchThread)
// and the handler ...
void Frame::OnSearchThread(wxCommandEvent &event)
{
if( event.GetEventType() == wxEVT_SEARCH_THREAD_MATCHFOUND)
{
// wxEVT_SEARCH_THREAD_MATCHFOUND returns a SearchResultList
// which is defined as:
// typedef std::list<SearchResult> SearchResultList;
// see SearchResult for more details.
SearchResultList *res = (SearchResultList*)event.GetClientData();
SearchResultList::iterator iter = res->begin();
wxString msg;
for(; iter != res->end(); iter++){
msg.Append((*iter).GetMessage() + wxT("\n"));
}
m_debugWin->AppendText(msg);
delete res;
}
else if(event.GetEventType() == wxEVT_SEARCH_THREAD_SEARCHCANCELED)
{
// wxEVT_SEARCH_THREAD_SEARCHCANCELED sets a cancell message in the GetString() method of the
// the event and nothing more
m_debugWin->AppendText(event.GetString() + wxT("\n"));
}
else if(event.GetEventType() == wxEVT_SEARCH_THREAD_SEARCHEND)
{
// When search ended, a summary object is sent to user:
// The summary contains the number of files scanned and number of total matches found
// a GetMessage() is provided that formats a nice suammry string
SearchSummary *summary = (SearchSummary*)event.GetClientData();
m_debugWin->AppendText(summary->GetMessage() + wxT("\n"));
delete summary;
}
}
//--------------------------------------------------------------
// Clean up
//--------------------------------------------------------------
// before shutdown, it is recommended to stop the SearchThread and free
// its resources:
SearchThreadST::Get()->Stop();
SearchThreadST::Free();
You can use it as is, or just for reference,
HTH,
Eran