all tokens in a string are found by a thread-safe setup function and stored where they can be retrieved one by one without calling strtok again. Thus, while the setup function would lock a common mutex and serialize access across all threads, the information retrieval function could run without any serialization.
8 Hints to avoid debugging
'Other maps are such shapes, with their islands and capes!
But we've got our brave Captain to thank'
(So the crew would protest)
'that he's bought us the best—
A perfect and absolute blank!'
Writing a complicated threaded program is a lot harder than writing a simple synchronous program, but once you learn the rules it is not much harder than writing a complicated synchronous program. Writing a threaded program to perform a complicated
The complications begin when you need to debug or analyze your threaded program. That's not so much because using threads is hard, but rather because the tools for debugging and analyzing threaded code are less well developed and understood than the programming interfaces. You may feel as if you are navigating from a blank map. That doesn't mean you can't utilize the power of threaded programming right now, but it does mean that you need to be careful, and maybe a little more creative, in avoiding the rocks and shoals of the uncharted waters.
Although this chapter mentions some thread debugging and analysis tools and suggests what you can accomplish with them, my goal isn't to tell you about tools you can use to solve problems. Instead, I will describe some of the common problems that you may encounter and impart something resembling 'sage advice' on avoiding those problems before you have to debug them — or, perhaps more realistically, how to recognize which problems you may be encountering.
Check your assumptions at the door.
Threaded programming is probably new to you. Asynchronous programming may be new to you. If so, you'll need to be careful about your assumptions. You've crossed a bridge, and behavior that's acceptable—or even required — in Synchronous Land can be dangerous across the river in Asynchronous Land. You can learn the new rules without a lot of trouble, and with practice you'll probably even feel comfortable with them. But you have to start by being constantly aware that something's changed.
8.1 Avoiding incorrect code
'For instance, now,' she went on, sticking a large piece of plaster on her finger as she spoke, 'there's the King's Messenger. He's in prison now, being punished: and the trial doesn't even begin till next Wednesday: and of course the crime comes last of all.'
'Suppose he never commits the crime?' said Alice.
'That would be all the better, wouldn't it?' the Queen said, as she bound the plaster round her finger with a bit of ribbon.
Pthreads doesn't provide much assistance in debugging your threaded code. That is not surprising, since POSIX does not recognize the concept of debugging at all, even in explaining why the nearly universal SIGTRAP signal is not included in the standard. There is no standard way to interact with your program or observe its behavior as it runs, although every threaded system will provide some form of debugging tool. Even in the unlikely event that the developers of the system had no concern for you, the poor programmer, they needed to debug their own code.
A vendor that provides threads with an operating system will provide at least a basic thread 'observation window' in a debugging utility. You should expect at minimum the ability to display a list of the running threads and their current state, the state of mutexes and condition variables, and the stack trace of all threads. You should also be able to set breakpoints in specified threads and specify a 'current thread' to examine registers, variables, and stack traces.
Because implementations of Pthreads are likely to maintain a lot of state in user mode, within the process, debugging using traditional UNIX mechanisms such as ptrace or the proc file system can be difficult. A common solution is to provide a special library that is called by the debugger, which knows how to search through the address space of the process being debugged to find the state of threads and synchronization objects. Solaris, for example, provides the libthread_db.so
shared library, and Digital UNIX provides libpthreaddebug.so
.
A thread package placed on top of an operating system by a third party will not be able to provide much integration with a debugger. For example, the portable 'DCE threads' library provides a built-in debug command parser that you can invoke from the debugger using the print or call command to report the state of threads and synchronization objects within the process[8]. This limited debugging support is at best inconvenient — you can't analyze thread state within a core file after a program has failed, and it cannot understand (or report) the symbolic names of program variables.
The following sections describe some of the most common classes of threaded programming errors, with the intention of helping you to avoid these problems while designing, as well as possibly making it easier to recognize them while debugging.
8.1.1 Avoid relying on 'thread inertia'
Always,
The same phenomenon may occur even on a multiprocessor, if you have reached the 'concurrency limit' of the process, for example, when you have more
This means that the thread that currently has a processor has an advantage. It tends to remain in motion, exhibiting behavior vaguely akin to physical inertia. As a result, you may get away with errors that will cause your code to break in mysterious ways when the newly created or awakened thread is able to run immediately — when