Here, code: in classbrowser.cpp line 726
THREAD_LOCKER_ENTER(s_TokensTreeCritical);
s_TokensTreeCritical.Enter();
THREAD_LOCKER_ENTERED(s_TokensTreeCritical);
THREAD_LOCKER_LEAVE(s_TokensTreeCritical);
s_TokensTreeCritical.Leave();
Why?
Here, code: in classbrowser.cpp line 726
THREAD_LOCKER_ENTER(s_TokensTreeCritical);
s_TokensTreeCritical.Enter();
THREAD_LOCKER_ENTERED(s_TokensTreeCritical);
THREAD_LOCKER_LEAVE(s_TokensTreeCritical);
s_TokensTreeCritical.Leave();
Why?
You found a bug, it should be:
THREAD_LOCKER_LEAVE(s_TokensTreeCritical);
s_TokensTreeCritical.Leave();
Copy and paste error. :-(
Can I express my opinion that this macros are super ugly. Why don't you convert them to single lines?
Something like:
#define CB_LOCKER_ENTER(lock) \
THREAD_LOCKER_ENTER(lock); \
lock.Enter(); \
THREAD_LOCKER_ENTERED(lock);
#define CB_LOCKER_LEAVE(lock) \
THREAD_LOCKER_LEAVE(lock); \
lock.Leave();
Well it's too late for that after you've spent many hours... but I would just have made my own locker class identical to the original wxMutexLocker with logging added in constructor and destructor, and added a #define wxMutexLocker myLoggingMutexLocker when desired. When exactly the section is entered and left is clear: enter when the locker object is created, leave when the scope ends (next closing curly brace).
The macro can have the current function and line information
#define THREAD_LOCKER_ENTER(NAME) \
CCLogger::Get()->DebugLog(F(_T("%s.Enter() : %s(), %s, %d"), \
wxString(#NAME, wxConvUTF8).wx_str(), \
wxString(__FUNCTION__, wxConvUTF8).wx_str(), \
wxString(__FILE__, wxConvUTF8).wx_str(), \
__LINE__))
#define THREAD_LOCKER_ENTERED(NAME) \
CCLogger::Get()->DebugLog(F(_T("%s.Entered() : %s(), %s, %d"), \
wxString(#NAME, wxConvUTF8).wx_str(), \
wxString(__FUNCTION__, wxConvUTF8).wx_str(), \
wxString(__FILE__, wxConvUTF8).wx_str(), \
__LINE__))
#define THREAD_LOCKER_LEAVE(NAME) \
CCLogger::Get()->DebugLog(F(_T("%s.Leave() : %s(), %s, %d"), \
wxString(#NAME, wxConvUTF8).wx_str(), \
wxString(__FUNCTION__, wxConvUTF8).wx_str(), \
wxString(__FILE__, wxConvUTF8).wx_str(), \
__LINE__))
How can you reference the caller in the locker's destructor?
Why are there so many locks/unlocks anyway? I counted 85 in the 3 CC files, that seems like an awful lot. I've never really touched code completion because it always scared me off... but naively thought, wouldn't one normally want to parse one complete file at a time (in N threads), and only lock/unlock the shared data structure to flush in all newly parsed tokens once after finishing each file? Something like that?
There are too many lockers(I hate them :)), because we want to access to the TokensTree from either GUI or working thread. So, we need at least a locker of the TokensTree.
The other reason is that: wxString is not thread safe(wxString is reference counted, but the counter is not thread safe, std::string is reference counted, but its counter is thread safe)
Edit:
wxWidgets 2.9.x use std::string/std::wstring internally for wxString, thus it is much safer than 2.8.x version.
How can you reference the caller in the locker's destructor?
A good reason for the macros, btw. ;-)
Not really ;)
First, being agnostic of a better solution, you can get this very effect by wrapping the locker's constructor in a macro and forwarding the constants. You'll still have a macro, but you'll retain exception safety and avoid generating more deadlocks.
Second, it's not necessary at all, since gcc allows you to query a function's return address without any hassle. addr2line translates the address back. I'm using this technique in one of my projects to track where an exception that made it to the outermost handler came from, this works like a charm.
There are too many lockers [...] access to the TokensTree from either GUI or working thread
Ok, this is a reason for one locker, but not for many. Normally, the high-level flow of a worker would be something like this:
while(get_next_file())
{
while(token = parse())
my_list.push_back(token);
do{
locker(lock);
for(auto t : my_list) ParseTree.add(t);
}while(0);
}
Of course you wouldn't just store tokens in a list (makes the example simpler, though). But nothing hinders you to build your own parse sub-tree and have a function that merges a sub-tree into the main tree, that's just an implementation detail.
other reason is [...] wxString is not thread safe
No reason, really. Strings are only ever modified from one thread concurrently.