Formal testing for multithreaded code

Started by
14 comments, last by chairthrower 15 years, 9 months ago
In fairness, while unit testing is far from foolproof, you can develop some tests for multi-threaded code, as long as you do it under the understanding that knowing the test passed doesn't necessarily mean your multi-threaded code will always work under those same input parameters. In particular, I had worked on one system where we used such a technique to detect potential deadlocks. We could dynamically configure things so the mutexes and semaphores would timeout if they were locked longer than expected. If a mutex or semaphore timed out and raised an exception, we would know about it, knew where things were when they deadlocked and it would give some indication of how to solve things.

In general though, multi-threaded code is among the most difficult to test reliably, and is one of the areas where the TDD books will say unit testing isn't the best mechanism for approaching it.

As a general response, I agree with ToohrVyk about multi-threading recklessly being dangerous. If you limit the scope of the code that has to be aware of the multi-threading, you can eliminate most of the risk involved.
Advertisement
It's not unit testing, but I recently attended a talk given by Andreas Zeller, and I think what he had to say might be relevant. His focus is to provide automatic assistance during debugging to make debugging a less onerous effort. You can see how this has direct links to formal testing.

Anyway, he was pretty enthusastic about the potential for automated debugging techniques to detect and assist in the correction of problems in concurrent environments. His research on Delta Debugging is here, and most of his work is open source.

http://www.st.cs.uni-sb.de/dd/

His work on threads involved some secret IBM tech, but he does explain what the IBM system had that made this possible. Here's the paper: http://www.st.cs.uni-sb.de/papers/issta2002/.
If you're interested, I implemented the Boost.Thread API in terms of user space threads (Fibers on Windows, <ucontext.h> on POSIX). It allows you test algorithmic correctness in isolation from synchronization correctness. Or looking at it another way, it provides a mock for threads.

You'll still need your stress tests and so on of course, but every little helps.

Currently, it matches the boost 1.34 threads API. I still need to update to 1.35.
Quote:if you're interested, I implemented the Boost.Thread API in terms of user space threads (Fibers on Windows, <ucontext.h> on POSIX). It allows you test algorithmic correctness in isolation from synchronization correctness. Or looking at it another way, it provides a mock for threads.


Wow!!, You wouldn't by any chance implement a coroutine interface on top of the boost::thread api would you ? i have looked at the boost coroutine thing/attempt/submission that i think wasnt accepted in the past quickly and it looked arbitrarily complex - i think you had to carry around a context as a template specialisation or something

apologies for not pursuing the link - its almost midnight at work here and i have to leave and will loose the connection, but will check it out first instance tommorow.
Quote:Original post by chairthrower
Quote:if you're interested, I implemented the Boost.Thread API in terms of user space threads (Fibers on Windows, <ucontext.h> on POSIX). It allows you test algorithmic correctness in isolation from synchronization correctness. Or looking at it another way, it provides a mock for threads.


Wow!!, You wouldn't by any chance implement a coroutine interface on top of the boost::thread api would you ? i have looked at the boost coroutine thing/attempt/submission that i think wasnt accepted in the past quickly and it looked arbitrarily complex - i think you had to carry around a context as a template specialisation or something


I wouldn't :) But! It should be very easy to do yourself. My thread class has a schedule function that you can use to force a context switch.

You may also be interested in this thread on the boost developers mailing list. The conclusion is that I may implement my library in terms of boost.coroutine because it was recently refactored to make it more suitable for this kind of thing; you may also want to look at Boost.Coroutine again.

EDIT: it would be irresponsible of me to not mention that I wouldn't use either Boost.Coroutine or my implementation of Boost.Thread in production code. The interaction with C++ language constructs is sparsely documented and rather fragile. For example, fibers work in conjunction with the DWARF exception handling mechanism, but not SJLJ exceptions. Also the POSIX API for user-space threads has been deprecated.

But it's still fun to play with and serves it purpose as a testing tool rather well, I think.
well i was going to say that your project sounded very worthy of boost inclusion consideration - but you beat me to it ;-). its amazing how far c++ can be made work - thanks for the information and context.

This topic is closed to new replies.

Advertisement