modify interface of sync.condition

This commit is contained in:
mutouyun 2021-10-23 17:27:08 +08:00
parent 4ddc1d0a3d
commit d946ad0948
10 changed files with 33 additions and 195 deletions

View File

@ -27,8 +27,8 @@ public:
void close() noexcept;
bool wait(ipc::sync::mutex &mtx, std::uint64_t tm = ipc::invalid_value) noexcept;
bool notify() noexcept;
bool broadcast() noexcept;
bool notify(ipc::sync::mutex &mtx) noexcept;
bool broadcast(ipc::sync::mutex &mtx) noexcept;
private:
class condition_;

View File

@ -115,7 +115,7 @@ public:
return true;
}
bool notify() noexcept {
bool notify(ipc::sync::mutex &) noexcept {
if (!valid()) return false;
int eno;
if ((eno = ::pthread_cond_signal(cond_)) != 0) {
@ -125,7 +125,7 @@ public:
return true;
}
bool broadcast() noexcept {
bool broadcast(ipc::sync::mutex &) noexcept {
if (!valid()) return false;
int eno;
if ((eno = ::pthread_cond_broadcast(cond_)) != 0) {

View File

@ -89,7 +89,7 @@ public:
return rs && rl;
}
bool notify() noexcept {
bool notify(ipc::sync::mutex &) noexcept {
if (!valid()) return false;
auto &cnt = counter();
if (!lock_.lock()) return false;
@ -101,7 +101,7 @@ public:
return lock_.unlock() && ret;
}
bool broadcast() noexcept {
bool broadcast(ipc::sync::mutex &) noexcept {
if (!valid()) return false;
auto &cnt = counter();
if (!lock_.lock()) return false;

View File

@ -58,12 +58,12 @@ bool condition::wait(ipc::sync::mutex &mtx, std::uint64_t tm) noexcept {
return impl(p_)->cond_.wait(mtx, tm);
}
bool condition::notify() noexcept {
return impl(p_)->cond_.notify();
bool condition::notify(ipc::sync::mutex &mtx) noexcept {
return impl(p_)->cond_.notify(mtx);
}
bool condition::broadcast() noexcept {
return impl(p_)->cond_.broadcast();
bool condition::broadcast(ipc::sync::mutex &mtx) noexcept {
return impl(p_)->cond_.broadcast(mtx);
}
} // namespace sync

View File

@ -63,12 +63,12 @@ public:
bool notify() noexcept {
std::lock_guard<ipc::sync::mutex>{lock_}; // barrier
return cond_.notify();
return cond_.notify(lock_);
}
bool broadcast() noexcept {
std::lock_guard<ipc::sync::mutex>{lock_}; // barrier
return cond_.broadcast();
return cond_.broadcast(lock_);
}
bool quit_waiting() {

View File

@ -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 45 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).

View File

@ -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_);
}

View File

@ -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

View File

@ -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

View File

@ -113,7 +113,7 @@ TEST(Sync, Condition) {
auto job = [&que](int num) {
ipc::sync::condition cond {"test-cond"};
ipc::sync::mutex lock {"test-mutex"};
for (;;) {
for (int i = 0; i < 10; ++i) {
int val = 0;
{
std::lock_guard<ipc::sync::mutex> guard {lock};
@ -123,6 +123,19 @@ TEST(Sync, Condition) {
val = que.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) {
std::printf("test-cond-%d: exit.\n", num);
return;
@ -139,16 +152,16 @@ TEST(Sync, Condition) {
{
std::lock_guard<ipc::sync::mutex> guard {lock};
que.push_back(i);
ASSERT_TRUE(cond.notify(lock));
}
cond.notify();
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
for (int i = 1; i < 100; ++i) {
{
std::lock_guard<ipc::sync::mutex> guard {lock};
que.push_back(i);
ASSERT_TRUE(cond.broadcast(lock));
}
cond.broadcast();
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) {
que.push_back(0);
}
ASSERT_TRUE(cond.broadcast(lock));
}
cond.broadcast();
for (auto &t : test_conds) t.join();
}
@ -171,7 +184,7 @@ TEST(Sync, ConditionRobust) {
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2\n");
ipc::sync::mutex lock {"test-mutex"};
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 3\n");
lock.lock();
ASSERT_TRUE(lock.lock());
std::thread unlock {[] {
printf("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 1\n");
ipc::sync::condition cond {"test-cond"};
@ -183,13 +196,13 @@ TEST(Sync, ConditionRobust) {
}
std::this_thread::sleep_for(std::chrono::seconds(1));
printf("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 4\n");
cond.broadcast();
ASSERT_TRUE(cond.broadcast(lock));
printf("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 5\n");
}};
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 4\n");
cond.wait(lock);
ASSERT_TRUE(cond.wait(lock));
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 5\n");
lock.unlock();
ASSERT_TRUE(lock.unlock());
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 6\n");
unlock.join();
}