Simplifies ThreadStartSemaphore's implementation.

This commit is contained in:
zhanyong.wan 2010-02-26 05:42:53 +00:00
parent 4f874c187b
commit c85a77a6ab
3 changed files with 33 additions and 64 deletions

View File

@ -220,6 +220,7 @@
#include <regex.h> // NOLINT #include <regex.h> // NOLINT
#include <strings.h> // NOLINT #include <strings.h> // NOLINT
#include <sys/types.h> // NOLINT #include <sys/types.h> // NOLINT
#include <time.h> // NOLINT
#include <unistd.h> // NOLINT #include <unistd.h> // NOLINT
#define GTEST_USES_POSIX_RE 1 #define GTEST_USES_POSIX_RE 1
@ -935,28 +936,41 @@ class ThreadLocal {
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
}; };
// Sleeps for (roughly) n milli-seconds. This function is only for
// testing Google Test's own constructs. Don't use it in user tests,
// either directly or indirectly.
inline void SleepMilliseconds(int n) {
const timespec time = {
0, // 0 seconds.
n * 1000L * 1000L, // And n ms.
};
nanosleep(&time, NULL);
}
// Allows a controller thread to pause execution of newly created // Allows a controller thread to pause execution of newly created
// threads until signalled. Instances of this class must be created // threads until signalled. Instances of this class must be created
// and destroyed in the controller thread. // and destroyed in the controller thread.
// //
// This class is supplied only for testing Google Test's own // This class is only for testing Google Test's own constructs. Do not
// constructs. Do not use it in user tests, either directly or indirectly. // use it in user tests, either directly or indirectly.
class ThreadStartSemaphore { class ThreadStartSemaphore {
public: public:
ThreadStartSemaphore(); ThreadStartSemaphore() : signalled_(false) {}
~ThreadStartSemaphore();
// Signals to all threads created with this semaphore to start. Must // Signals to all threads created with this semaphore to start. Must
// be called from the controller thread. // be called from the controller thread.
void Signal(); void Signal() { signalled_ = true; }
// Blocks until the controller thread signals. Must be called from a test // Blocks until the controller thread signals. Must be called from a test
// thread. // thread.
void Wait(); void Wait() {
while(!signalled_) {
SleepMilliseconds(10);
}
}
private: private:
// We cannot use Mutex here as this class is intended for testing it. volatile bool signalled_;
pthread_mutex_t mutex_;
pthread_cond_t cond_;
bool signalled_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadStartSemaphore); GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadStartSemaphore);
}; };
@ -971,8 +985,8 @@ class ThreadStartSemaphore {
// ThreadWithParam<int> thread(&ThreadFunc, 5, &semaphore); // ThreadWithParam<int> thread(&ThreadFunc, 5, &semaphore);
// semaphore.Signal(); // Allows the thread to start. // semaphore.Signal(); // Allows the thread to start.
// //
// This class is supplied only for testing Google Test's own // This class is only for testing Google Test's own constructs. Do not
// constructs. Do not use it in user tests, either directly or indirectly. // use it in user tests, either directly or indirectly.
template <typename T> template <typename T>
class ThreadWithParam { class ThreadWithParam {
public: public:

View File

@ -75,46 +75,6 @@ const int kStdOutFileno = STDOUT_FILENO;
const int kStdErrFileno = STDERR_FILENO; const int kStdErrFileno = STDERR_FILENO;
#endif // _MSC_VER #endif // _MSC_VER
#if GTEST_HAS_PTHREAD
// ThreadStartSemaphore allows the controller thread to pause execution of
// newly created test threads until signalled. Instances of this class must
// be created and destroyed in the controller thread.
ThreadStartSemaphore::ThreadStartSemaphore() : signalled_(false) {
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_init(&cond_, NULL));
pthread_mutex_lock(&mutex_);
}
ThreadStartSemaphore::~ThreadStartSemaphore() {
// Every ThreadStartSemaphore object must be signalled. It locks
// internal mutex upon creation and Signal unlocks it.
GTEST_CHECK_(signalled_);
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_));
GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_destroy(&cond_));
}
// Signals to all test threads to start. Must be called from the
// controlling thread.
void ThreadStartSemaphore::Signal() {
signalled_ = true;
GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_signal(&cond_));
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_));
}
// Blocks until the controlling thread signals. Should be called from a
// test thread.
void ThreadStartSemaphore::Wait() {
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_));
while (!signalled_) {
GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_wait(&cond_, &mutex_));
}
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_));
}
#endif // GTEST_HAS_PTHREAD
#if GTEST_OS_MAC #if GTEST_OS_MAC
// Returns the number of threads running in the process, or 0 to indicate that // Returns the number of threads running in the process, or 0 to indicate that

View File

@ -35,10 +35,6 @@
#include <stdio.h> #include <stdio.h>
#if GTEST_HAS_PTHREAD
#include <unistd.h> // For nanosleep().
#endif // GTEST_HAS_PTHREAD
#if GTEST_OS_MAC #if GTEST_OS_MAC
#include <time.h> #include <time.h>
#endif // GTEST_OS_MAC #endif // GTEST_OS_MAC
@ -137,10 +133,7 @@ TEST(GetThreadCountTest, ReturnsCorrectValue) {
if (GetThreadCount() == 1) if (GetThreadCount() == 1)
break; break;
timespec time; SleepMilliseconds(100);
time.tv_sec = 0;
time.tv_nsec = 100L * 1000 * 1000; // .1 seconds.
nanosleep(&time, NULL);
} }
EXPECT_EQ(1U, GetThreadCount()); EXPECT_EQ(1U, GetThreadCount());
pthread_mutex_destroy(&mutex); pthread_mutex_destroy(&mutex);
@ -802,7 +795,7 @@ TEST(ThreadLocalTest, PointerAndConstPointerReturnSameValue) {
} }
#if GTEST_IS_THREADSAFE #if GTEST_IS_THREADSAFE
TEST(MutexTestDeathTest, AssertHeldShouldAssertWhenNotLocked) { TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked) {
// AssertHeld() is flaky only in the presence of multiple threads accessing // AssertHeld() is flaky only in the presence of multiple threads accessing
// the lock. In this case, the test is robust. // the lock. In this case, the test is robust.
EXPECT_DEATH_IF_SUPPORTED({ EXPECT_DEATH_IF_SUPPORTED({
@ -813,8 +806,10 @@ TEST(MutexTestDeathTest, AssertHeldShouldAssertWhenNotLocked) {
"The current thread is not holding the mutex @.+"); "The current thread is not holding the mutex @.+");
} }
void SleepMilliseconds(int time) { TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked) {
usleep(static_cast<useconds_t>(time * 1000.0)); Mutex m;
MutexLock lock(&m);
m.AssertHeld();
} }
class AtomicCounterWithMutex { class AtomicCounterWithMutex {
@ -873,7 +868,7 @@ TEST(MutexTest, OnlyOneThreadCanLockAtATime) {
kCycleCount), kCycleCount),
&semaphore)); &semaphore));
} }
semaphore.Signal(); // Start the threads. semaphore.Signal(); // Starts the threads.
for (int i = 0; i < kThreadCount; ++i) for (int i = 0; i < kThreadCount; ++i)
counting_threads[i]->Join(); counting_threads[i]->Join();