| 1 | #include <boost/date_time.hpp>
|
|---|
| 2 | #include <boost/thread/mutex.hpp>
|
|---|
| 3 | #include <boost/thread/thread.hpp>
|
|---|
| 4 | #include <iostream>
|
|---|
| 5 |
|
|---|
| 6 | // Number should be big enough to allow context switch between threads, otherwise the bug doesn't show.
|
|---|
| 7 | static int MAX_COUNTS;
|
|---|
| 8 |
|
|---|
| 9 | class ItemKeeper {
|
|---|
| 10 |
|
|---|
| 11 | public:
|
|---|
| 12 | ItemKeeper() { }
|
|---|
| 13 |
|
|---|
| 14 | void doSomething() {
|
|---|
| 15 | boost::mutex::scoped_lock scoped_lock(mutex);
|
|---|
| 16 | int counts = MAX_COUNTS;
|
|---|
| 17 | while (counts--);
|
|---|
| 18 | }
|
|---|
| 19 |
|
|---|
| 20 | private:
|
|---|
| 21 | boost::mutex mutex;
|
|---|
| 22 | };
|
|---|
| 23 |
|
|---|
| 24 | ItemKeeper itemKeeper;
|
|---|
| 25 |
|
|---|
| 26 | int MAX_ITERATIONS(5);
|
|---|
| 27 |
|
|---|
| 28 | void threadFunc(int invokerID, bool& exceptionOccurred) {
|
|---|
| 29 | try {
|
|---|
| 30 | for (int i = 0; i < MAX_ITERATIONS; i++) {
|
|---|
| 31 | std::cout << "Thread " << invokerID << ", iteration " << i << std::endl;
|
|---|
| 32 | itemKeeper.doSomething();
|
|---|
| 33 | }
|
|---|
| 34 | } catch (...) {
|
|---|
| 35 | exceptionOccurred = true;
|
|---|
| 36 | }
|
|---|
| 37 | }
|
|---|
| 38 |
|
|---|
| 39 |
|
|---|
| 40 | int main(int argc, char* argv[]) {
|
|---|
| 41 | if (argc < 2) {
|
|---|
| 42 | MAX_COUNTS = 5000000;
|
|---|
| 43 | } else {
|
|---|
| 44 | std::string valueStr(argv[1]);
|
|---|
| 45 | bool has_only_digits = (valueStr.find_first_not_of( "0123456789" ) == std::string::npos);
|
|---|
| 46 | if (has_only_digits) {
|
|---|
| 47 | std::istringstream aStream(valueStr);
|
|---|
| 48 | aStream >> MAX_COUNTS;
|
|---|
| 49 | } else {
|
|---|
| 50 | std::cerr << "Argument should be an integer\n";
|
|---|
| 51 | return 1;
|
|---|
| 52 | }
|
|---|
| 53 | }
|
|---|
| 54 |
|
|---|
| 55 | bool exceptionOccurred1(false);
|
|---|
| 56 | bool exceptionOccurred2(false);
|
|---|
| 57 |
|
|---|
| 58 | boost::thread thread1(threadFunc, 1, boost::ref(exceptionOccurred1));
|
|---|
| 59 | boost::thread thread2(threadFunc, 2, boost::ref(exceptionOccurred2));
|
|---|
| 60 |
|
|---|
| 61 | boost::posix_time::time_duration timeout = boost::posix_time::milliseconds(10000);
|
|---|
| 62 |
|
|---|
| 63 | bool deadlockOccured(false);
|
|---|
| 64 |
|
|---|
| 65 | if (!thread1.timed_join(timeout)) {
|
|---|
| 66 | deadlockOccured = true;
|
|---|
| 67 | thread1.interrupt();
|
|---|
| 68 | }
|
|---|
| 69 | if (!thread2.timed_join(timeout)) {
|
|---|
| 70 | deadlockOccured = true;
|
|---|
| 71 | thread2.interrupt();
|
|---|
| 72 | }
|
|---|
| 73 |
|
|---|
| 74 | if (deadlockOccured) {
|
|---|
| 75 | std::cout << "Deadlock occurred\n";
|
|---|
| 76 | }
|
|---|
| 77 | if (exceptionOccurred1 || exceptionOccurred2) {
|
|---|
| 78 | std::cout << "Exception occurred\n";
|
|---|
| 79 | }
|
|---|
| 80 | }
|
|---|
| 81 |
|
|---|