mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
modify interface of sync.condition
This commit is contained in:
parent
4ddc1d0a3d
commit
d946ad0948
@ -27,8 +27,8 @@ public:
|
|||||||
void close() noexcept;
|
void close() noexcept;
|
||||||
|
|
||||||
bool wait(ipc::sync::mutex &mtx, std::uint64_t tm = ipc::invalid_value) noexcept;
|
bool wait(ipc::sync::mutex &mtx, std::uint64_t tm = ipc::invalid_value) noexcept;
|
||||||
bool notify() noexcept;
|
bool notify(ipc::sync::mutex &mtx) noexcept;
|
||||||
bool broadcast() noexcept;
|
bool broadcast(ipc::sync::mutex &mtx) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class condition_;
|
class condition_;
|
||||||
|
|||||||
@ -115,7 +115,7 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool notify() noexcept {
|
bool notify(ipc::sync::mutex &) noexcept {
|
||||||
if (!valid()) return false;
|
if (!valid()) return false;
|
||||||
int eno;
|
int eno;
|
||||||
if ((eno = ::pthread_cond_signal(cond_)) != 0) {
|
if ((eno = ::pthread_cond_signal(cond_)) != 0) {
|
||||||
@ -125,7 +125,7 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool broadcast() noexcept {
|
bool broadcast(ipc::sync::mutex &) noexcept {
|
||||||
if (!valid()) return false;
|
if (!valid()) return false;
|
||||||
int eno;
|
int eno;
|
||||||
if ((eno = ::pthread_cond_broadcast(cond_)) != 0) {
|
if ((eno = ::pthread_cond_broadcast(cond_)) != 0) {
|
||||||
|
|||||||
@ -89,7 +89,7 @@ public:
|
|||||||
return rs && rl;
|
return rs && rl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool notify() noexcept {
|
bool notify(ipc::sync::mutex &) noexcept {
|
||||||
if (!valid()) return false;
|
if (!valid()) return false;
|
||||||
auto &cnt = counter();
|
auto &cnt = counter();
|
||||||
if (!lock_.lock()) return false;
|
if (!lock_.lock()) return false;
|
||||||
@ -101,7 +101,7 @@ public:
|
|||||||
return lock_.unlock() && ret;
|
return lock_.unlock() && ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool broadcast() noexcept {
|
bool broadcast(ipc::sync::mutex &) noexcept {
|
||||||
if (!valid()) return false;
|
if (!valid()) return false;
|
||||||
auto &cnt = counter();
|
auto &cnt = counter();
|
||||||
if (!lock_.lock()) return false;
|
if (!lock_.lock()) return false;
|
||||||
|
|||||||
@ -58,12 +58,12 @@ bool condition::wait(ipc::sync::mutex &mtx, std::uint64_t tm) noexcept {
|
|||||||
return impl(p_)->cond_.wait(mtx, tm);
|
return impl(p_)->cond_.wait(mtx, tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool condition::notify() noexcept {
|
bool condition::notify(ipc::sync::mutex &mtx) noexcept {
|
||||||
return impl(p_)->cond_.notify();
|
return impl(p_)->cond_.notify(mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool condition::broadcast() noexcept {
|
bool condition::broadcast(ipc::sync::mutex &mtx) noexcept {
|
||||||
return impl(p_)->cond_.broadcast();
|
return impl(p_)->cond_.broadcast(mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sync
|
} // namespace sync
|
||||||
|
|||||||
@ -63,12 +63,12 @@ public:
|
|||||||
|
|
||||||
bool notify() noexcept {
|
bool notify() noexcept {
|
||||||
std::lock_guard<ipc::sync::mutex>{lock_}; // barrier
|
std::lock_guard<ipc::sync::mutex>{lock_}; // barrier
|
||||||
return cond_.notify();
|
return cond_.notify(lock_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool broadcast() noexcept {
|
bool broadcast() noexcept {
|
||||||
std::lock_guard<ipc::sync::mutex>{lock_}; // barrier
|
std::lock_guard<ipc::sync::mutex>{lock_}; // barrier
|
||||||
return cond_.broadcast();
|
return cond_.broadcast(lock_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool quit_waiting() {
|
bool quit_waiting() {
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
# A Quick Introduction to C++ Performance Tuning
|
|
||||||
(From: https://github.com/adah1972/cpp_summit_2020.git)
|
|
||||||
|
|
||||||
This repository contains the presentation file and example code for my
|
|
||||||
presentation at the C++ Summit 2020 held in Shenzhen, China on 4–5 December
|
|
||||||
2020.
|
|
||||||
|
|
||||||
The presentation content is shared under a [Creative Commons Attribution-Share
|
|
||||||
Alike 2.5 Licence](http://creativecommons.org/licenses/by-sa/2.5/). The code
|
|
||||||
is put in the public domain (i.e. do whatever you like with it), though an
|
|
||||||
acknowledgement will be appreciated (but not required).
|
|
||||||
@ -1,77 +0,0 @@
|
|||||||
#include "profiler.h"
|
|
||||||
#include <cassert>
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
struct profiling_data {
|
|
||||||
int number;
|
|
||||||
int call_count{};
|
|
||||||
uint64_t call_duration{};
|
|
||||||
};
|
|
||||||
|
|
||||||
class profiler {
|
|
||||||
public:
|
|
||||||
profiler();
|
|
||||||
~profiler();
|
|
||||||
|
|
||||||
void add_data(int number, uint64_t duration);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<profiling_data> data_;
|
|
||||||
};
|
|
||||||
|
|
||||||
profiler::profiler()
|
|
||||||
{
|
|
||||||
size_t len = 0;
|
|
||||||
for (;;) {
|
|
||||||
if (name_map[len].name == NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++len;
|
|
||||||
}
|
|
||||||
data_.resize(len);
|
|
||||||
int i = 0;
|
|
||||||
for (auto& item : data_) {
|
|
||||||
assert(i == name_map[i].number);
|
|
||||||
item.number = i;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
profiler::~profiler()
|
|
||||||
{
|
|
||||||
#ifndef NDEBUG
|
|
||||||
for (auto& item : data_) {
|
|
||||||
if (item.call_count == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
std::cout << item.number << " " << name_map[item.number].name
|
|
||||||
<< ":\n";
|
|
||||||
std::cout << " Call count: " << item.call_count << '\n';
|
|
||||||
std::cout << " Call duration: " << item.call_duration << '\n';
|
|
||||||
std::cout << " Average duration: "
|
|
||||||
<< item.call_duration * 1.0 /
|
|
||||||
(item.call_count != 0 ? item.call_count : 1)
|
|
||||||
<< '\n';
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void profiler::add_data(int number, uint64_t duration)
|
|
||||||
{
|
|
||||||
assert(number >= 0 && number < static_cast<int>(data_.size()));
|
|
||||||
data_[number].call_count++;
|
|
||||||
data_[number].call_duration += duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
profiler profiler_instance;
|
|
||||||
|
|
||||||
} // unnamed namespace
|
|
||||||
|
|
||||||
profiling_checker::~profiling_checker()
|
|
||||||
{
|
|
||||||
auto end_time = rdtsc();
|
|
||||||
profiler_instance.add_data(number_, end_time - start_time_);
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
#ifndef PROFILER_H
|
|
||||||
#define PROFILER_H
|
|
||||||
|
|
||||||
#include "rdtsc.h"
|
|
||||||
|
|
||||||
struct name_mapper {
|
|
||||||
int number;
|
|
||||||
const char* name;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern name_mapper name_map[];
|
|
||||||
|
|
||||||
class profiling_checker {
|
|
||||||
public:
|
|
||||||
profiling_checker(int number);
|
|
||||||
~profiling_checker();
|
|
||||||
|
|
||||||
private:
|
|
||||||
int number_;
|
|
||||||
uint64_t start_time_;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline profiling_checker::profiling_checker(int number)
|
|
||||||
: number_(number)
|
|
||||||
{
|
|
||||||
start_time_ = rdtsc();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#define PROFILE_CHECK(func_number) (void)0
|
|
||||||
#else
|
|
||||||
#define PROFILE_CHECK(func_number) profiling_checker _checker(func_number)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // PROFILER_H
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
#ifndef RDTSC_H
|
|
||||||
#define RDTSC_H
|
|
||||||
|
|
||||||
#include <stdint.h> // uint64_t
|
|
||||||
|
|
||||||
#if defined(_M_X64) || defined(_M_IX86) || defined(__x86_64) || defined(__i386)
|
|
||||||
# ifdef _WIN32
|
|
||||||
# include <intrin.h> // __rdtsc
|
|
||||||
# else
|
|
||||||
# include <x86intrin.h> // __rdtsc
|
|
||||||
# endif
|
|
||||||
# define HAS_HW_RDTSC 1
|
|
||||||
#else
|
|
||||||
# include <chrono> // std::chrono::high_resolution_clock
|
|
||||||
# define HAS_HW_RDTSC 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inline uint64_t rdtsc()
|
|
||||||
{
|
|
||||||
#if HAS_HW_RDTSC
|
|
||||||
// _mm_lfence() might be used to serialize the instruction stream,
|
|
||||||
// and it would guarantee that RDTSC will not be reordered with
|
|
||||||
// other instructions. However, measurements show that the overhead
|
|
||||||
// may be too big (easily 15 to 30 CPU cycles) for profiling
|
|
||||||
// purposes: if reordering matters, the overhead matters too!
|
|
||||||
|
|
||||||
// Forbid the compiler from reordering instructions
|
|
||||||
# ifdef _MSC_VER
|
|
||||||
_ReadWriteBarrier();
|
|
||||||
# else
|
|
||||||
__asm__ __volatile__("" : : : "memory");
|
|
||||||
# endif
|
|
||||||
|
|
||||||
uint64_t result = __rdtsc();
|
|
||||||
|
|
||||||
// Forbid the compiler from reordering instructions
|
|
||||||
# ifdef _MSC_VER
|
|
||||||
_ReadWriteBarrier();
|
|
||||||
# else
|
|
||||||
__asm__ __volatile__("" : : : "memory");
|
|
||||||
# endif
|
|
||||||
|
|
||||||
return result;
|
|
||||||
#else
|
|
||||||
auto now = std::chrono::high_resolution_clock::now();
|
|
||||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
|
||||||
now.time_since_epoch())
|
|
||||||
.count();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // RDTSC_H
|
|
||||||
@ -113,7 +113,7 @@ TEST(Sync, Condition) {
|
|||||||
auto job = [&que](int num) {
|
auto job = [&que](int num) {
|
||||||
ipc::sync::condition cond {"test-cond"};
|
ipc::sync::condition cond {"test-cond"};
|
||||||
ipc::sync::mutex lock {"test-mutex"};
|
ipc::sync::mutex lock {"test-mutex"};
|
||||||
for (;;) {
|
for (int i = 0; i < 10; ++i) {
|
||||||
int val = 0;
|
int val = 0;
|
||||||
{
|
{
|
||||||
std::lock_guard<ipc::sync::mutex> guard {lock};
|
std::lock_guard<ipc::sync::mutex> guard {lock};
|
||||||
@ -123,6 +123,19 @@ TEST(Sync, Condition) {
|
|||||||
val = que.front();
|
val = que.front();
|
||||||
que.pop_front();
|
que.pop_front();
|
||||||
}
|
}
|
||||||
|
EXPECT_NE(val, 0);
|
||||||
|
std::printf("test-cond-%d: %d\n", num, val);
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
int val = 0;
|
||||||
|
{
|
||||||
|
std::lock_guard<ipc::sync::mutex> guard {lock};
|
||||||
|
while (que.empty()) {
|
||||||
|
EXPECT_TRUE(cond.wait(lock, 1000));
|
||||||
|
}
|
||||||
|
val = que.front();
|
||||||
|
que.pop_front();
|
||||||
|
}
|
||||||
if (val == 0) {
|
if (val == 0) {
|
||||||
std::printf("test-cond-%d: exit.\n", num);
|
std::printf("test-cond-%d: exit.\n", num);
|
||||||
return;
|
return;
|
||||||
@ -139,16 +152,16 @@ TEST(Sync, Condition) {
|
|||||||
{
|
{
|
||||||
std::lock_guard<ipc::sync::mutex> guard {lock};
|
std::lock_guard<ipc::sync::mutex> guard {lock};
|
||||||
que.push_back(i);
|
que.push_back(i);
|
||||||
|
ASSERT_TRUE(cond.notify(lock));
|
||||||
}
|
}
|
||||||
cond.notify();
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
}
|
}
|
||||||
for (int i = 1; i < 100; ++i) {
|
for (int i = 1; i < 100; ++i) {
|
||||||
{
|
{
|
||||||
std::lock_guard<ipc::sync::mutex> guard {lock};
|
std::lock_guard<ipc::sync::mutex> guard {lock};
|
||||||
que.push_back(i);
|
que.push_back(i);
|
||||||
|
ASSERT_TRUE(cond.broadcast(lock));
|
||||||
}
|
}
|
||||||
cond.broadcast();
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -156,8 +169,8 @@ TEST(Sync, Condition) {
|
|||||||
for (int i = 0; i < (int)test_conds.size(); ++i) {
|
for (int i = 0; i < (int)test_conds.size(); ++i) {
|
||||||
que.push_back(0);
|
que.push_back(0);
|
||||||
}
|
}
|
||||||
|
ASSERT_TRUE(cond.broadcast(lock));
|
||||||
}
|
}
|
||||||
cond.broadcast();
|
|
||||||
|
|
||||||
for (auto &t : test_conds) t.join();
|
for (auto &t : test_conds) t.join();
|
||||||
}
|
}
|
||||||
@ -171,7 +184,7 @@ TEST(Sync, ConditionRobust) {
|
|||||||
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2\n");
|
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2\n");
|
||||||
ipc::sync::mutex lock {"test-mutex"};
|
ipc::sync::mutex lock {"test-mutex"};
|
||||||
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 3\n");
|
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 3\n");
|
||||||
lock.lock();
|
ASSERT_TRUE(lock.lock());
|
||||||
std::thread unlock {[] {
|
std::thread unlock {[] {
|
||||||
printf("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 1\n");
|
printf("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 1\n");
|
||||||
ipc::sync::condition cond {"test-cond"};
|
ipc::sync::condition cond {"test-cond"};
|
||||||
@ -183,13 +196,13 @@ TEST(Sync, ConditionRobust) {
|
|||||||
}
|
}
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
printf("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 4\n");
|
printf("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 4\n");
|
||||||
cond.broadcast();
|
ASSERT_TRUE(cond.broadcast(lock));
|
||||||
printf("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 5\n");
|
printf("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 5\n");
|
||||||
}};
|
}};
|
||||||
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 4\n");
|
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 4\n");
|
||||||
cond.wait(lock);
|
ASSERT_TRUE(cond.wait(lock));
|
||||||
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 5\n");
|
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 5\n");
|
||||||
lock.unlock();
|
ASSERT_TRUE(lock.unlock());
|
||||||
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 6\n");
|
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 6\n");
|
||||||
unlock.join();
|
unlock.join();
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user