thread_terror.cpp (2257B)
1 #include <trompeloeil.hpp> 2 #include <iterator> 3 #include <thread> 4 #include <atomic> 5 #include <iostream> 6 #include <cassert> 7 8 class C 9 { 10 public: 11 MAKE_MOCK0(func, int(void)); 12 std::unique_ptr<trompeloeil::expectation> allow; 13 }; 14 15 static std::mutex ptr_mutex; 16 inline auto get_lock() 17 { 18 return std::unique_lock<std::mutex>{ ptr_mutex }; 19 } 20 21 static std::shared_ptr<C> obj; 22 23 inline std::shared_ptr<C> get_obj() 24 { 25 auto lock = get_lock(); 26 return obj; 27 } 28 29 static std::atomic<std::size_t> call_count[7]; 30 static std::atomic<std::size_t> ret_count[7]; 31 32 static void init_obj() 33 { 34 auto m = std::make_shared<C>(); 35 m->allow = NAMED_ALLOW_CALL(*m, func()) 36 .SIDE_EFFECT(++call_count[0]) 37 .RETURN(0); 38 auto lock = get_lock(); 39 obj = m; 40 } 41 42 static void make(size_t count) 43 { 44 while (count--) 45 { 46 init_obj(); 47 } 48 } 49 50 static void call(size_t count) 51 { 52 while (count--) 53 { 54 if (auto m = get_obj()) 55 { 56 ret_count[m->func()]++; 57 } 58 } 59 } 60 61 static void allow(size_t count, int id) 62 { 63 std::unique_ptr<trompeloeil::expectation> exp; 64 while (count--) 65 { 66 if (auto m = get_obj()) 67 { 68 exp = NAMED_ALLOW_CALL(*m, func()) 69 .SIDE_EFFECT(++call_count[id]) 70 .RETURN(id); 71 assert(exp->is_satisfied()); 72 assert(!exp->is_saturated()); 73 } 74 } 75 } 76 77 int main() 78 { 79 trompeloeil::set_reporter([](auto , auto , auto, auto&) 80 { 81 abort(); 82 }); 83 init_obj(); 84 85 size_t count = 100000; 86 std::vector<std::thread> allowers; 87 std::vector<std::thread> callers; 88 allowers.reserve(6); 89 callers.reserve(6); 90 auto maker = std::thread(make, count); 91 for (int i = 1; i <= 6; ++i) 92 { 93 allowers.emplace_back(allow, count, i); 94 callers.emplace_back(call, count); 95 } 96 for (auto& t : callers) t.join(); 97 for (auto& t : allowers) t.join(); 98 maker.join(); 99 std::cout << "calls "; 100 std::copy(std::begin(call_count), std::end(call_count), 101 std::ostream_iterator<std::size_t>(std::cout, " ")); 102 std::cout << "\nreturns "; 103 std::copy(std::begin(ret_count), std::end(ret_count), 104 std::ostream_iterator<std::size_t>(std::cout, " ")); 105 std::cout << "\n"; 106 assert(std::equal(std::begin(call_count), std::end(call_count), 107 std::begin(ret_count), std::end(ret_count))); 108 obj.reset(); 109 }