void IntQueue::pushInt(int n) { d_mutexSem.wait(); d_queue.push_front(n); d_mutexSem.post(); d_resourceSem.post(); }
int IntQueue::getInt() { // Waiting for resources. d_resourceSem.wait(); // 'd_mutexSem' is used for exclusive access. d_mutexSem.wait(); int ret = d_queue.back(); d_queue.pop_back(); d_mutexSem.post(); return ret; }
int main(int argc, char *argv[]) { int test = argc > 1 ? atoi(argv[1]) : 0; int verbose = argc > 2; cout << "TEST " << __FILE__ << " CASE " << test << endl; switch (test) { case 0: // Zero is always the leading case. case 6: { ///Usage ///----- // This component is an implementation detail of 'bslmt' and is *not* intended // for direct client use. It is subject to change without notice. As such, a // usage example is not provided. // USAGE EXAMPLE IntQueue testQueue; testQueue.pushInt(1); ASSERT(1 == testQueue.getInt()); testQueue.pushInt(2); ASSERT(2 == testQueue.getInt()); } break; case 5: { // -------------------------------------------------------------------- // TESTING 'tryWait' // // Concerns: // 1. 'tryWait' decrements the count if resources are available, // or return an error otherwise. // // Plan: // We create two groups of threads. One will call 'post', the other // 'tryWait'. First, we make sure that 'tryWait' fails if no // resources are available. Then we will make sure it succeeds if // resources are. We will also test 'tryWait' in the steady state // works fine. // // Testing: // void tryWait(); // -------------------------------------------------------------------- if (verbose) cout << endl << "Testing 'trywait'" << endl << "=================" << endl; bslmt::ThreadUtil::Handle threads[10]; MyBarrier barrier(10); Obj sem; struct ThreadInfo5 info; info.d_numIterations = 5000; // number of ops per thread / 3 info.d_barrier = &barrier; info.d_sem = &sem; for (int i = 0; i < 5; ++i) { ASSERT(0 == bslmt::ThreadUtil::create(&threads[i * 2], thread5Post, &info)); ASSERT(0 == bslmt::ThreadUtil::create(&threads[i * 2 + 1], thread5Wait, &info)); } for (int i = 0; i < 10; ++i) { ASSERT(0 == bslmt::ThreadUtil::join(threads[i])); } } break; case 4: { // -------------------------------------------------------------------- // TESTING 'post(int)' // // Concerns: // 1. post(int) increments the count by the expected number // // Plan: // Create a set of threads calling 'wait' and use a thread to post a // number smaller than the set of threads. // // Testing: // void post(int number); // -------------------------------------------------------------------- if (verbose) cout << endl << "Testing 'post(int number)'" << endl << "==========================" << endl; bslmt::ThreadUtil::Handle threads[6]; MyBarrier barrier(6); Obj sem; struct ThreadInfo4 info; info.d_numIterations = 10000; // number of ops per thread info.d_numWaitThreads = 5; info.d_barrier = &barrier; info.d_sem = &sem; for (int i = 0; i < 5; ++i) { ASSERT(0 == bslmt::ThreadUtil::create(&threads[i], thread4Wait, &info)); } ASSERT(0 == bslmt::ThreadUtil::create(&threads[5], thread4Post, &info)); for (int i = 0; i < 6; ++i) { ASSERT(0 == bslmt::ThreadUtil::join(threads[i])); } } break; case 3: { // -------------------------------------------------------------------- // TESTING 'timedWait' // // Concerns: // 1. timedWait() blocks the thread until a resource is available // or the timeout expires. // // Plan: // Create two groups of threads one will call 'post' and the other // will call 'timedWait'. First, we will make sure that the // 'timedWait' will timeout properly if no resource available by // calling the function with a reasonable timeout before any calls to // 'post'. Then, both groups of threads will enter a loop to simulate // the steady state. The 'post' loop will be perturbed to exercise // different portions of code. The specified timeout will be pretty // important and we will make sure we do not timeout. At the end // of this first run, we will make a second run with a much lower // timeout which will force *some* waits to timeout. // // Testing: // void timedWait(bsls::TimeInterval timeout, // int *signalInterrupted = 0); // -------------------------------------------------------------------- if (verbose) cout << endl << "Testing 'timedWait'" << endl << "===================" << endl; testCase3(bsls::SystemClockType::e_REALTIME); testCase3(bsls::SystemClockType::e_MONOTONIC); } break; case 2: { // -------------------------------------------------------------------- // TESTING 'wait' and 'post' // // Concerns: // 1. wait() blocks the thread when no resource is available, // and then decrements the count // 2. post() increments the count // // Plan: // Create two groups of threads one will call 'post' and the other // will call 'wait'. To address concern 1, we will use a barrier and // a counter to make sure that waiting threads are blocked into wait // state before any calls to 'post'. After that, we will try to reach // a steady state by calling the two functions in a loop and perturb // the 'post' operation by adding small delays to exercise different // parts of the code. // // Testing: // void post(); // void wait(int *signalInterrupted = 0); // -------------------------------------------------------------------- if (verbose) cout << endl << "Testing 'wait' and 'post'" << endl << "=========================" << endl; bslmt::ThreadUtil::Handle threads[10]; MyBarrier barrier(6); bsls::AtomicInt past(0); Obj sem; struct ThreadInfo2 info; info.d_numIterations = 10000; // number of ops per thread info.d_barrier = &barrier; info.d_sem = &sem; info.d_past = &past; for (int i = 0; i < 5; ++i) { ASSERT(0 == bslmt::ThreadUtil::create(&threads[i * 2], thread2Post, &info)); ASSERT(0 == bslmt::ThreadUtil::create(&threads[i * 2 + 1], thread2Wait, &info)); } bslmt::ThreadUtil::microSleep(1000 * 100); ASSERT(0 == past); barrier.wait(); bslmt::ThreadUtil::microSleep(1000 * 200); ASSERT(0 != past); for (int i = 0; i < 10; ++i) { ASSERT(0 == bslmt::ThreadUtil::join(threads[i])); } } break; case 1: { // -------------------------------------------------------------------- // BREATHING TEST: // // Exercises basic functionality. // -------------------------------------------------------------------- if (verbose) cout << endl << "Breathing Test" << endl << "==============" << endl; { Obj X; X.post(); X.post(2); X.wait(); ASSERT(0 == X.timedWait(bsls::SystemTime::nowRealtimeClock() + bsls::TimeInterval(60))); ASSERT(0 == X.tryWait()); ASSERT(0 != X.tryWait()); ASSERT(0 != X.timedWait(bsls::SystemTime::nowRealtimeClock() + bsls::TimeInterval(1))); } } break; default: { cerr << "WARNING: CASE `" << test << "' NOT FOUND." << endl; testStatus = -1; } } if (testStatus > 0) { cerr << "Error, non-zero test status = " << testStatus << "." << endl; } return testStatus; }