00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef TEST_ATOMIC_H_
00020 #define TEST_ATOMIC_H_
00021
00022 #include <cppunit/extensions/HelperMacros.h>
00023 #include <cppunit/TestAssert.h>
00024 #include "baseTest.h"
00025 #include <amino/cstdatomic>
00026 #include <iostream>
00027
00028 using namespace std;
00029
00030
00034 template<class ParaType>
00035 class AtomicTest :public CppUnit::TestFixture{
00036 CPPUNIT_TEST_SUITE(AtomicTest);
00037 CPPUNIT_TEST(testAcqRel);
00038 CPPUNIT_TEST_SUITE_END();
00039
00040 public:
00041 AtomicTest() {
00042 }
00043
00044 void setUp() {
00045 }
00046
00047 void reset() {
00048 }
00049
00050 void tearDown() {
00051 }
00052
00062 void testAcqRel();
00063 };
00064
00065 class IntProducer{
00066 private:
00067 atomic<bool> * _flag;
00068 volatile int * _product;
00069 public:
00070 IntProducer(atomic<bool> & flag, volatile int & product){
00071 _flag = &flag;
00072 _product = &product;
00073 }
00074
00075 void operator()(){
00076 int opCount = TestConfig::getInstance()->getOperationNum();
00077 for(int i=0;i<opCount;i++){
00078
00079 while(_flag->load(memory_order_acquire))
00080 {}
00081
00082 (*_product) = i;
00083
00084 _flag->store(true, memory_order_release);
00085 }
00086 }
00087 };
00088
00089 class IntConsumer{
00090 private:
00091 atomic<bool> * _flag;
00092 volatile int * _product;
00093 public:
00094 volatile bool error;
00095
00096 IntConsumer(atomic<bool> & flag, volatile int & product){
00097 _flag = &flag;
00098 _product = &product;
00099
00100 error = false;
00101 }
00102
00103 void operator()(){
00104 int opCount = TestConfig::getInstance()->getOperationNum();
00105
00106 for(int i=0;i<opCount;i++){
00107
00108 while(!_flag->load(memory_order_acquire))
00109 {}
00110
00111 if(*_product != i)
00112 error = true;
00113
00114 _flag->store(false, memory_order_release);
00115 }
00116 }
00117 };
00118
00119 template<typename ParaType>
00120 void AtomicTest<ParaType>::testAcqRel() {
00121
00122
00123
00124
00125 atomic<bool> flag;
00126 flag = false;
00127
00128 volatile int product;
00129 product = 0;
00130
00131 IntProducer producer(flag, product);
00132 IntConsumer consumer(flag, product);
00133
00134 Thread thread1(producer);
00135 Thread thread2(consumer);
00136
00137 thread1.join();
00138 thread2.join();
00139
00140 CPPUNIT_ASSERT(!consumer.error);
00141 }
00142
00146 template<class ParaType, char const* CLASS_NAME>
00147 class AtomicNumTest:public CppUnit::TestFixture{
00148 CPPUNIT_TEST_SUITE(AtomicNumTest);
00149 CPPUNIT_TEST(testPlusSub);
00150 CPPUNIT_TEST_SUITE_END();
00151
00152 private:
00153 atomic<ParaType> fVar;
00154 public:
00155 AtomicNumTest() {
00156 }
00157
00158 atomic<ParaType> * getAtomic(){
00159 return &fVar;
00160 }
00161
00162 void setUp() {
00163 fVar = 0;
00164 }
00165
00166 void reset() {
00167 }
00168
00169 void tearDown() {
00170 }
00171
00172 void testPlusSub();
00173 };
00174
00175 template<class ParaType, char const* CLASS_NAME>
00176 class ThreadMath : public TestThread<ParaType> {
00177 private:
00178 atomic<ParaType> * atomic_var;
00179 AtomicNumTest<ParaType, CLASS_NAME> * test;
00180 int operationNum;
00181 public:
00182
00183 ThreadMath(atomic<ParaType> * var, AtomicNumTest<ParaType, CLASS_NAME> * test_case,
00184 int nOperation) :
00185 atomic_var(var), test(test_case), operationNum(nOperation) {
00186 }
00187
00192 void* run() {
00193 for (int i = 0; i< operationNum; ++i) {
00194 if(i%2 == 0){
00195 (*atomic_var)++;
00196 ParaType oldV = atomic_var->load();
00197 do{
00198 }while(!atomic_var->compare_swap(oldV, oldV+1));
00199 }
00200 else{
00201 (*atomic_var)--;
00202 ParaType oldV = atomic_var->load();
00203 do{
00204 }while(!atomic_var->compare_swap(oldV, oldV-1));
00205 }
00206 }
00207 return NULL;
00208 }
00209 };
00210
00211 template<class ParaType, char const* CLASS_NAME> class MathThreadFactory :
00212 public ThreadFactory<ParaType> {
00213 private:
00214 atomic<ParaType> * atomic_var;
00215 AtomicNumTest<ParaType, CLASS_NAME> * test;
00216 public:
00217
00218 MathThreadFactory(atomic<ParaType> * s, AtomicNumTest<ParaType, CLASS_NAME> * test_case) :
00219 atomic_var(s), test(test_case)
00220 {
00221 }
00222
00223 virtual Runnable** createThreads(int threadNum, int elementNum, int operationNum) {
00224 test->reset();
00225 atomic_var = test->getAtomic();
00226 this->inVec.clear();
00227 this->outVec.clear();
00228
00229 typedef Runnable* pRunnable;
00230 pRunnable* threads;
00231 threads = new pRunnable[threadNum];
00232 for (int i=0; i<threadNum; i++) {
00233 threads[i] = new ThreadMath<ParaType, CLASS_NAME>(atomic_var, test, operationNum);
00234 }
00235 return threads;
00236 }
00237
00238 virtual void verifyResult(int threadNum, int elementNum) {
00239 CPPUNIT_ASSERT(atomic_var->load() == 0);
00240 }
00241 };
00242
00243 template<class ParaType, char const* CLASS_NAME>
00244 void AtomicNumTest<ParaType, CLASS_NAME>::testPlusSub() {
00245 MathThreadFactory<ParaType, CLASS_NAME> factory(&fVar, this);
00246 ThreadRunner::runThreads(&factory, CLASS_NAME, "testPlusSub");
00247 }
00248 #endif