| | |
| | | // printf("client Recv reply : %s\n", reply.data().c_str()); |
| | | } |
| | | |
| | | class TLMutex |
| | | { |
| | | // typedef boost::interprocess::interprocess_mutex MutexT; |
| | | typedef CasMutex MutexT; |
| | | // typedef std::mutex MutexT; |
| | | typedef std::chrono::steady_clock Clock; |
| | | typedef Clock::duration Duration; |
| | | static Duration Now() { return Clock::now().time_since_epoch(); } |
| | | |
| | | const Duration limit_; |
| | | std::atomic<Duration> last_lock_time_; |
| | | MutexT mutex_; |
| | | |
| | | public: |
| | | struct Status { |
| | | int64_t nlock_ = 0; |
| | | int64_t nupdate_time_fail = 0; |
| | | int64_t nfail = 0; |
| | | int64_t nexcept = 0; |
| | | }; |
| | | Status st_; |
| | | |
| | | explicit TLMutex(Duration limit) : |
| | | limit_(limit) {} |
| | | TLMutex() : |
| | | TLMutex(std::chrono::seconds(1)) {} |
| | | ~TLMutex() { static_assert(std::is_pod<Duration>::value); } |
| | | bool try_lock() |
| | | { |
| | | if (mutex_.try_lock()) { |
| | | auto old_time = last_lock_time_.load(); |
| | | if (Now() - old_time > limit_) { |
| | | return last_lock_time_.compare_exchange_strong(old_time, Now()); |
| | | } else { |
| | | last_lock_time_.store(Now()); |
| | | return true; |
| | | } |
| | | } else { |
| | | auto old_time = last_lock_time_.load(); |
| | | if (Now() - old_time > limit_) { |
| | | return last_lock_time_.compare_exchange_strong(old_time, Now()); |
| | | } else { |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | void lock() |
| | | { |
| | | int n = 0; |
| | | while (!try_lock()) { |
| | | n++; |
| | | std::this_thread::yield(); |
| | | } |
| | | st_.nlock_ += n; |
| | | } |
| | | void unlock() { mutex_.unlock(); } |
| | | }; |
| | | |
| | | namespace |
| | | { |
| | | typedef int64_t Offset; |
| | | Offset Addr(void *ptr) { return reinterpret_cast<Offset>(ptr); } |
| | | void *Ptr(const Offset offset) { return reinterpret_cast<void *>(offset); } |
| | | } // namespace |
| | | |
| | | BOOST_AUTO_TEST_CASE(MutexTest) |
| | | { |
| | | const std::string shm_name("ShmMutex"); |
| | | // ShmRemover auto_remove(shm_name); |
| | | SharedMemory shm(shm_name, 1024 * 1024 * 10); |
| | | SharedMemory &shm = TestShm(); |
| | | MsgI::BindShm(shm); |
| | | |
| | | void *base_ptr = shm.get_address(); |
| | | auto PrintPtr = [&](void *p) { |
| | | printf("addr: %ld, ptr: %p, offset: %ld\n", Addr(p), p, Addr(p) - Addr(base_ptr)); |
| | | }; |
| | | |
| | | printf("base"); |
| | | PrintPtr(base_ptr); |
| | | |
| | | MsgI msg; |
| | | msg.Make("string data"); |
| | | for (int i = 0; i < 10; ++i) { |
| | | int n = msg.AddRef(); |
| | | printf("add %d ref: %d\n", i, n); |
| | | } |
| | | for (int i = 0; i < 10; ++i) { |
| | | int n = msg.Release(); |
| | | printf("release %d, ref : %d\n", i, n); |
| | | } |
| | | std::this_thread::sleep_for(1s); |
| | | msg.Release(); |
| | | |
| | | const std::string mtx_name("test_mutex"); |
| | | const std::string int_name("test_int"); |
| | | auto mtx = shm.find_or_construct<Mutex>(mtx_name.c_str())(); |
| | | auto pi = shm.find_or_construct<int>(int_name.c_str())(100); |
| | | |
| | | printf("mutetx "); |
| | | PrintPtr(mtx); |
| | | printf("int "); |
| | | PrintPtr(pi); |
| | | |
| | | typedef std::chrono::steady_clock Clock; |
| | | auto Now = []() { return Clock::now().time_since_epoch(); }; |
| | | if (pi) { |
| | | auto old = *pi; |
| | | printf("int : %d, add1: %d\n", old, ++*pi); |
| | | } |
| | | |
| | | { |
| | | boost::timer::auto_cpu_timer timer; |
| | | printf("test time: "); |
| | | TLMutex mutex; |
| | | // CasMutex mutex; |
| | | auto Lock = [&]() { |
| | | for (int i = 0; i < 1000 * 100; ++i) { |
| | | mutex.lock(); |
| | | mutex.unlock(); |
| | | } |
| | | }; |
| | | std::thread t1(Lock), t2(Lock); |
| | | t1.join(); |
| | | t2.join(); |
| | | printf("mutex nlock: %ld, update time error: %ld, normal fail: %ld, error wait: %ld\n", |
| | | mutex.st_.nlock_, |
| | | mutex.st_.nupdate_time_fail, |
| | | mutex.st_.nfail, |
| | | mutex.st_.nexcept); |
| | | } |
| | | |
| | | auto MSFromNow = [](const int ms) { |
| | | using namespace boost::posix_time; |
| | | ptime cur = boost::posix_time::microsec_clock::universal_time(); |
| | | return cur + millisec(ms); |
| | | }; |
| | | |
| | | auto TryLock = [&]() { |
| | | if (mtx->try_lock()) { |
| | |
| | | if (mtx) { |
| | | printf("mtx exists\n"); |
| | | if (TryLock()) { |
| | | if (TryLock()) { |
| | | Unlock(); |
| | | } |
| | | auto op = [&]() { |
| | | if (TryLock()) { |
| | | Unlock(); |
| | | } |
| | | }; |
| | | op(); |
| | | std::thread t(op); |
| | | t.join(); |
| | | // Unlock(); |
| | | } else { |
| | | // mtx->unlock(); |
| | | } |
| | | } else { |
| | | printf("mtx not exists\n"); |