Rss Feed
Tweeter button
Facebook button
Technorati button
Reddit button
Myspace button
Linkedin button
Webonews button
Delicious button
Digg button
Flickr button
Stumbleupon button
Newsvine button

Category: Thread

Thread naming

By , June 19, 2019 7:21 pm

Multi-threading is becoming quite common these days. It’s a useful way to provide a responsive user interface while performing work at the same time. Our tools report data per thread where that is warranted (per-thread code coverage doesn’t seem to be a thing – no one has requested it in 17 years). In this article I’m going to discuss thread naming, OS support for thread naming, and additional support for thread naming that our tools automatically provide.

The Default Thread Display

Threads are represented by a thread handle and a thread id. Typically the thread id is what will be used to represent the thread in a user interface reporting thread related data. Thread ids are numeric. For example: 341. For trivial programs you can often infer which thread is which by looking at the data allocated on each thread. However that doesn’t scale very well to more complex applications. You can end up with thread displays like this:


Microsoft Thread Naming Exception

The WIN32 API does not provide any functions to allow you to name a thread. To handle this oversight, Microsoft use a convention that allows a program to communicate a thread name with it’s debugger. This is done via means of an exception that the program throws (and then catches to prevent it’s propagation terminating the application). The debugger also catches this exception and with the help of ReadProcessMemory() can retrieve the exception name from the program. Here’s how that works.

In your program

The exception code that identifies a thread naming exception is 0x406D1388. To pass the thread name to the debugger you need to create a struct of type THREADNAME_INFO (definition shown int the code sample), populate it with the appropriate data then raise an exception with the specified exception code. You’ll need to use SEH __try/__except to surround the RaiseException() call to prevent crashing the program.

void nameThread(const DWORD	threadId,
                const char	*name)
{
	// You can name your threads by using the following code. 
	// Thread Validator will intercept the exception and pass it along (so if you are also running
	// under a debugger the debugger will also see the exception and read the thread name

	// NOTE: this is for 'unmanaged' C++ ONLY!

	#define MS_VC_EXCEPTION 0x406D1388
	#define BUFFER_LEN		16

	typedef struct tagTHREADNAME_INFO
	{
		DWORD	dwType;		// must be 0x1000
		LPCSTR	szName;		// pointer to name (in user addr space) buffer must be 8 chars + 1 terminator
		DWORD	dwThreadID;	// thread ID (-1 == caller thread)
		DWORD	dwFlags;	// reserved for future use, must be zero
	} THREADNAME_INFO;

	THREADNAME_INFO	ThreadInfo;
	char		szSafeThreadName[BUFFER_LEN];	// buffer can be any size, just make sure it is large enough!
	
	memset(szSafeThreadName, 0, sizeof(szSafeThreadName));	// ensure all characters are NULL before
	strncpy(szSafeThreadName, name, BUFFER_LEN - 1);	// copying name
	//szSafeThreadName[BUFFER_LEN - 1] = '\0';

	ThreadInfo.dwType = 0x1000;
	ThreadInfo.szName = szSafeThreadName;
	ThreadInfo.dwThreadID = threadId;
	ThreadInfo.dwFlags = 0;

	__try
	{
		RaiseException(MS_VC_EXCEPTION, 0, 
                               sizeof(ThreadInfo) / sizeof(DWORD_PTR), 
                               (DWORD_PTR *)&ThreadInfo); 
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{
		// do nothing, just catch the exception so that you don't terminate the application
	}
}

In the debugger

The thread name is communicated to the debugger in event.u.Exception.ExceptionRecord.ExceptionInformation[1]. This pointer can be read using ReadProcessMemory(). Once the debugger continues and this event goes out of scope, the ability to read the thread name no longer exists. If you want to read the thread name you must read it immediately, storing it for future use.

	if ((de->dwDebugEventCode == EXCEPTION_DEBUG_EVENT) &&
	    (de->u.Exception.ExceptionRecord.ExceptionCode == SVL_THREAD_NAMING_EXCEPTION))
	{
		char	buffer[1000];
		int		bRet;
		SIZE_T	dwRead = 0;

		memset(buffer, 0, 1000);
		bRet = ReadProcessMemory(hProcess,
					 (void *)event.u.Exception.ExceptionRecord.ExceptionInformation[1],
					 buffer,
					 1000 - 1,	// remove one so there is always a terminating zero
					 &dwRead);

		setThreadName((DWORD)event.u.Exception.ExceptionRecord.ExceptionInformation[2], buffer);
	}

Our tools support intercepting this mechanism so that we can name your threads if you use this mechanism.

The problem with this mechanism is that it puts the onus for naming the threads on the creator of the application. If that involves 3rd party components that spawn their own threads, and OS threads then almost certainly not all threads will be named, which results in some threads having a name and other threads being represented by a thread id.


CreateThread() And Symbols

In an attempt to automatically name threads to provide useful naming for threads without having to rely on the author of a program using thread naming exceptions we started monitoring CreateThread() to get the thread start address, then resolve that address into a symbol name (assuming debugging symbols are available) and use that symbol name to represent the thread. After some tests (done with our own tools – which are heavily multithreaded – dog-fooding) we concluded this was a useful way to name threads.

However this doesn’t solve the problem as many threads are now named _threadstartex().


_beginthread(), _beginthreadex() And Symbols

The problem with the CreateThread() approach is that any threads created by calls to the C runtime functions _beginthread() or _beginthreadex() will result in the thread being called _threadstart() or _threadstartex(). This is because these functions pass their own thread function to CreateThread(). The way to solve this problem is to also monitor _beginthread() and _beginthreadex() functions to get the thread start address, then resolve that address into a symbol name.


Un-named Threads

Some threads still end up without names – typically these are transient threads created by the OS to do a short amount of work. If the call to create the thread was internal to Kernel32.dll then CreateThread() will not be called by an IAT call and will not be monitored, resulting in the thread not getting named automatically. This isn’t ideal, but ultimately you don’t control these threads, which means you can’t affect the data reported by these threads, so it’s not that important.

Thread Naming Priority

We’ve made these changes to all our Validator tools and updated the user interfaces to represent threads by both thread id and thread name.

If a thread is named by a thread naming exception or via a Software Verify API call that name will take precedence over any automatically named thread. This is useful in cases where the same function is used by many threads – you can if you wish give each thread a unique name to prevent multiple threads having the same name.

Here are some of the displays that have benefited from named threads.

Bug Validator


Memory Validator


Performance Validator


Thread Validator



64 bit C++ software tool Beta Tests are complete.

By , January 9, 2014 1:33 pm

We recently closed the beta tests for the 64 bit versions of C++ Coverage Validator, C++ Memory Validator, C++ Performance Validator and C++ Thread Validator.

We launched the software on 2nd January 2014. A soft launch, no fanfare, no publicity. We just wanted to make the software available and then contact all the beta testers so that we could honour our commitments made at the start of the beta test.

Those commitments were to provide a free single user licence to any beta tester that provided feedback, usage reports, bugs reports, etc about the software. This doesn’t include anyone that couldn’t install the software because they used the wrong licence key!

We’ve written a special app here that we can use to identify all email from beta test participants and allow us to evaluate that email for beta test feedback criteria. It’s saved us a ton of time and drudge work even though writing this extension to the licence manager software took a few days. It was interesting using the tool and seeing who provided feedback and how much.

We’ve just sent out the licence keys and download instructions to all those beta testers that were kind enough to take the time to provide feedback, bug reports etc. to us. A few people went the extra mile. These people bombarded us with email containing huge bugs, trivial items and everything in between. Two of them, we were on the verge of flying out to their offices when we found some useful software that allowed to us to remotely debug their software. Special mentions go to:

Bengt Gunne (Mimer.com)
Ciro Ettorre (Mechworks.com)
Kevin Ernst (Bentley.com)

We’re very grateful for everyone taking part in the beta test. Thank you very much.

Why didn’t I get a free licence?

If you didn’t receive a free licence and you think you did provide feedback, please contact us. It’s always possible that a few people slipped through our process of identifying people.

Dang! I knew I should’ve provided feedback

If you didn’t provide us with any feedback, check your inbox. You’ll find a 50% off coupon for the tool that you tested.

Thread Validator x64 enters BETA

By , August 6, 2010 8:57 am

Thread Validator x64 is now available for beta testing.

Thread locking history

Thread Validator x64 is the 64 bit version of our successful 32 bit Thread Validator software tool that runs on Microsoft Windows operating systems. Thread Validator x64 is a deadlock detection and thread analysis software tool, running on Windows 7 64 bit, Windows Vista 64 bit and Windows XP 64 bit.

Thread Validator has multiple displays to provide you with different perspectives onto the data you have collected.

What does Thread Validator do?

Thread Validator x64 identifies thread deadlocks, potential deadlocks and locks with a high contention rate.

Thread deadlocks usually mean that one or more threads can no longer function correctly because they are waiting on a lock that will never be released. This is an error condition and usually manifests as an unresponsive computer program.

Potential deadlocks are locking sequences that have not triggered a deadlock but may lead to a deadlock under slightly different conditions.

High contention rate locks result in your program spending too much time waiting for access to a lock. A different program design can often reduce a high contention rate to a less demanding contention rate.

How does Thread Validator work?

Thread Validator instruments your computer program so that it can monitor the appropriate synchronization APIs used to control access to locks, mutexes, semaphores and wait conditions. Using the information gained from monitoring these APIs, Thread Validator can calculate deadlock conditions, potential deadlock conditions and detect locks with high contention rates.

Thread Validator gathers data for all locks, all threads, all mutexes, all semaphores and all wait conditions. The data is organised into various displays allowing you to view information:

  • All active locks.
  • All active locks, organized by thread.
  • All locks that are locked at a given time.
  • Allocation information for all allocated synchronization objects, showing callstack and source code.
  • Thread locking history. View all threads, see what each threads is doing and when.
  • Thread lock order. View the order locks are acquired across threads for a given lock sequence.
  • List of all application objects that can be used in wait conditions.
  • How Thread Validator helps you be more productive

    Thread Validator x64 can help you:

    • Identify deadlocks in your application – quickly identify and fix hard threading problems.
    • Identify potential deadlocks in your application – prevent problems before they get serious.
    • Identify busy contended critical sections in your application – improve performance.
    • View thread locking behaviour in real time.
    • Improve your software quality by modifying your threading behaviour.
    • View all open handles that your application can wait on.

    Join the beta test

    If you are developing 64 bit software and have some multi-threading problems you would like to analyze, please join the beta, analyze your multi-threading problems and let us know your thoughts.

Thread monitoring made easy

By , April 30, 2010 10:36 am

Tools like Thread Validator are great for delving into the details of why a thread deadlock has occurred.You get all the gory details, DLL, filename, line number, lock, mutex, wait, sequence of lock acquisition on each thread. You can work out why the failure occurred.

But sometimes this is overkill, more than you need, for this particular bug. Perhaps you don’t think the bug is real, but just an artifact of how things are working. You don’t want to spend time in the heavyweight tool, not today, but perhaps next week.

What you want a tool with a lighter impact on the system. A tool that will just tell you that what you think is a problem, really is a problem, or actually is not a problem. If its not a problem you can just move on to the next topic, if it is a problem, time to get the serious tools out and investigate the problem.

That is where Thread Status Monitor is very useful. We wrote an early version of this tool some time ago. It was hosted on Object Media where we publish source code for some of our tools. We have improved the tool a bit and decided that it is a better fit on the Software Verification website.

Thread Status Monitor

Thread Status monitor tells you everything you need to know about each thread in a process. The thread id, its wait status, the wait reason, number of context switches, thread priority, how long the thread has spent waiting, how long the thread has been executing, how much CPU thread is currently consuming.

Where appropriate bar graphs are used to provide visual indicators as to which items are largest. Colour coding (pink/blue) is also used to indicate values increasing and decreasing, drawing your attention to the latest changes.

Thread Status Monitor Detail

Simply select the process you wish to monitor in the list at the top of the user interface and view the threads in the lower pane. You can change the refresh rate using the combo box and sort by clicking on the column header you want to sort.

Thread Status Monitor will be available in the next few days.

Thread Lock Checker now available

By , April 22, 2010 6:20 pm

We’ve just released Thread Lock Checker.

Took a bit longer than we anticipated (sorry about that) due to some website maintenance work. Anyway its available now, go and give your source code some TLC and find any latent lock errors in your code!

Thread Lock Checker

Improving how you use CSingleLock

By , April 2, 2010 9:44 pm

Thread Lock Checker Logo

This posting covers a brief background:

  • Win32 critical sections.
  • How CCriticalSection and CSingleLock can be used instead of Win32 critical sections.
  • An improved way to use CSingleLock.
  • Some ways CSingleLock can be used that do not have the desired effect.

Critical Sections in Win32

The Win32 API uses InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection and DeleteCriticalSection to manage critical sections (CRITICAL_SECTION). Using these APIs is not particularly hard, but nonetheless it is possible to use critical sections that have not been initialized or that have been deleted. It is also possible to forget to leave a critical section that has been entered. In addition, any exceptions that get thrown may result in a critical section being left in its locked state.

This can cause serious performance problems as locks are held for too long, or in the case of a lock not being released, it can prevent other threads gaining access to the resource the lock was protecting, possibly resulting in a deadlock.

Example Win32 usage (assume critical section initialized in a different function):

void someFunc()
{
	doWork();

	EnterCriticalSection(&cs);

	doWorkEx();

	LeaveCriticalSection(&cs);
}

Why use CSingleLock and CMultiLock?

When using critical sections in MFC you use the CCriticalSection class instead of CRITICAL_SECTION objects.

You can directly call Lock() and Unlock() on the CCriticalSection, but it is recommended that you use CSingleLock and CMultiLock to manage your CCriticalSection objects.

The benefits of using a class such as CSingleLock (and its related class CMultiLock) are that:

  • The CSingleLock manages the activities of entering and leaving the critical section – you do not have to think about the critical section at all.
  • Any CCriticalSection object used with CSingleLocks will automatically be initialized before the CSingleLock gets to work with it.
  • The CSingleLock is automatically unlocked (if it was locked) when the CSingleLock is deleted and thus the CCriticalSection that was associated with this CSingleLock is not held locked .
  • If an exception is thrown, C++ objects are cleaned up by the exception handling chain, thus automatically deleting any CSingleLock objects and releasing any locks they hold.
  • CSingleLock can be used to lock and unlock critical sections just like the old Win32 methods, allowing for easy conversion of code from Win32 style to CSingleLock style.
  • It is possible to create a CSingleLock that is automatically locked. This is very useful for set-and-forget critical section management. Just put the CSingleLock in the right place and you can ignore it in the rest of the code. Very neat, convenient and elegant.

One way of using CSingleLock

As described above a typical style of using CSingleLocks echoes the Win32 style of using critical sections.

void someFunc()
{
	CSingleLock	lock(&csSect);

	doWork();

	lock.Lock();
	doWorkEx();
	lock.Unlock();
}

As you can see, the CSingleLock lock manager is created, the doWork() function is called outside of the protected area, the lock is locked, doWorkEx() is called, then the lock is unlocked. This is a very similar style of writing to Win32 equivalent.

A better way of using CSingleLock

The problem with the previous way of using CSingleLock is that most of the power and convenience of CSingleLock is ignored. Lock management has been made explicit via calls to Lock() and Unlock(). This means there is potential for forgetting to lock the CSingleLock, or for unlocking the CSingleLock later than desirable.

An improved way of using CSingleLock is to always create CSingleLocks in the locked state and to create CSingleLocks as close to the resource they are need to protect.

The following example shows the same function written using a CSingleLock that is automatically locked, created just before it is required and automatically destroyed at the end of the function.

void someFunc()
{
	doWork();

	CSingleLock	lock(&csSect, TRUE);

	doWorkEx();
}

If I wanted to some more work after doWorkEx() but I didn’t want that protected by the lock I could do it by using C++’s scoping capabilities. I simply create a new scope and place the CSingleLock in there. At the end of the scope the CSingleLock is destroyed and the lock is unlocked.

void someFunc()
{
	doWork();

	{
		CSingleLock	lock(&csSect, TRUE);

		doWorkEx();
	}

	doMoreWork();
}

Some problems we have seen…

During the development of code for the software tools at Software Verification and our private tools we’ve found a few interesting mistakes. Mistakes often made not through poor design, but simply a typing oversight or mistake, possibly due to tiredness of the person working on the code – the type of mistake you can only put down to the fact that humans do make mistakes, not matter how talented they are in any given field.

Where possible we like to use the CSingleLock lock(&csSect, TRUE) automatic locking style coupled with tight scoping to make the lock lifetime short. As a result we are interested in find the following coding constructs which will result in errors in expected behaviour in our software:

  • CSingleLock created without a lock argument. This defaults to an unlocked CSingleLock.
    CSingleLock	lock(&csSect);
  • CSingleLock created with a FALSE lock argument. This is an unlocked CSingleLock.
    CSingleLock	lock(&csSect, FALSE);
  • CSingleLock created with a variable declaration. This compiles but creates a lock that is immediately destroyed. Any of these three variants are interesting as none of the are useful, but all compile OK.
    CSingleLock(&csSect);
    CSingleLock(&csSect, FALSE);
    CSingleLock(&csSect, TRUE);

Thread Lock Checker

Thread Lock Checker

The problem with the examples we show above is that looking for them is hard work because humans often read what they expect to read (this is part of our predictive pattern recognition built into how we process shapes and text). As a result you may be looking right an error and not see it, but you may see the error the next time you come to the code (having forgotten all about it).

To aid in the discovery of these types of lock usage (for both CSingleLock, CMultiLock and any named classes that have the same style of behaviour) we have written a software tool, Thread Lock Checker.

We use Thread Lock Checker before we release any software. We use Thread Lock Checker to scan our codebase looking for any mistakes not identified by our software engineers. Its a very useful tool. We hope that you will also find Thread Lock Checker useful. Please check back next week for your free download.

We will be releasing Thread Lock Checker during the week of 5 April to 9 April.

Support for MinGW and QtCreator

By , December 4, 2009 5:01 pm

Everyone uses Visual Studio to write C and C++ software don’t they? Yes! you all chorus. Apart from some guys at the back who like to use gcc and g++. They use MinGW when working on Windows. And they may even use Emacs, or perish the thought, vi!

Up until now we haven’t been able to cater to the needs of gcc and g++ users. We’d get email every month asking when we were going to support MinGW or if we supported QtCreator. It was frustrating admitting we couldn’t support that environment. Even more so as the founders of Software Verification wrote large GIS applications using gcc and g++ back in the early 1990s.

During October we integrated support for MinGW and QtCreator into Coverage Validator, Memory Validator, Performance Validator and Thread Validator. Both COFF and STABS debug formats are supported, which provides some flexibility in how you choose to handle your symbols.

We’ll continue to add support for additional compilers to our tools as long as there is interest from you, the kind people that use our software tools.

Panorama Theme by Themocracy