CPP Multi-Threading Codes
CPP Multi-Threading
#include <atomic>
#include <ctime>
#include <iostream>
#include <memory>
#include <mutex>
#include <numeric>
#include <thread>
#include <vector>
constexpr int THD_NUM = 20;
constexpr int CNT_PER_THD = 50000000;
using namespace std;
class Counter {
public:
virtual void operator++() {}
virtual int64_t get() const { return 0; }
virtual ~Counter() {}
};
class DistributedCounter : public Counter {
private:
int64_t count{};
std::mutex mutable mtx;
public:
void operator++() override {
std::lock_guard<std::mutex> lock(mtx);
++count;
}
int64_t get() const override {
std::lock_guard<std::mutex> lock(mtx);
return count;
}
};
class DistributedCounterMultMtx : public Counter {
struct bucket {
mutable std::mutex sm;
int64_t count{};
};
static size_t const buckets{THD_NUM};
std::vector<bucket> counts{buckets};
public:
void operator++() override {
size_t index =
std::hash<thread::id>()(std::this_thread::get_id()) % buckets;
std::lock_guard<std::mutex> ul(counts[index].sm);
++(counts[index].count);
}
int64_t get() const override {
return std::accumulate(counts.begin(), counts.end(), (int64_t)0,
[](auto acc, auto &x) {
std::lock_guard<std::mutex> sl(x.sm);
return acc + x.count;
});
}
};
class DistributedCounterMultMtxPadding : public Counter {
struct bucket {
mutable std::mutex sm;
int64_t count{};
char padding[256];
};
static size_t const buckets{THD_NUM};
std::vector<bucket> counts{buckets};
public:
void operator++() override {
size_t index =
std::hash<thread::id>()(std::this_thread::get_id()) % buckets;
std::lock_guard<std::mutex> ul(counts[index].sm);
counts[index].count++;
}
int64_t get() const override {
return std::accumulate(counts.begin(), counts.end(), (int64_t)0,
[](auto acc, auto &x) {
std::lock_guard<std::mutex> sl(x.sm);
return acc + x.count;
});
}
};
class DistributedCounterOneAtomic : public Counter {
private:
std::atomic<int64_t> count{};
public:
void operator++() { ++count; }
int64_t get() const override { return count; }
};
class DistributedCounterMultiAtomic : public Counter {
struct bucket {
std::atomic<int64_t> count;
};
static size_t const buckets{THD_NUM};
std::vector<bucket> counts{buckets};
public:
void operator++() override {
size_t index =
std::hash<thread::id>()(std::this_thread::get_id()) % buckets;
++(counts[index].count);
}
int64_t get() const override {
return std::accumulate(
counts.begin(), counts.end(), (int64_t)0,
[](auto acc, auto &x) { return acc + x.count.load(); });
}
};
class DistributedCounterMultiAtomicPadding : public Counter {
struct bucket {
std::atomic<int64_t> count;
char padding[256];
};
static size_t const buckets{THD_NUM};
std::vector<bucket> counts{buckets};
public:
void operator++() {
size_t index =
std::hash<thread::id>()(std::this_thread::get_id()) % buckets;
++(counts[index].count);
}
int64_t get() const override {
return std::accumulate(
counts.begin(), counts.end(), (int64_t)0,
[](auto acc, auto &x) { return acc + x.count.load(); });
}
};
int main() {
std::vector<std::pair<std::string, std::unique_ptr<Counter>>> counters;
counters.emplace_back("DistributedCounterMtx", new DistributedCounter);
counters.emplace_back("DistributedCounterMultMtx",
new DistributedCounterMultMtx);
counters.emplace_back("DistributedCounterMultMtxPadding",
new DistributedCounterMultMtxPadding);
counters.emplace_back("DistributedCounterOneAtomic",
new DistributedCounterOneAtomic);
counters.emplace_back("DistributedCounterMultiAtomic",
new DistributedCounterMultiAtomic);
counters.emplace_back("DistributedCounterMultiAtomicPadding",
new DistributedCounterMultiAtomicPadding);
for (auto &p : counters) {
time_t t;
const auto start = std::time(&t);
std::vector<std::thread> thds;
auto t_num = THD_NUM;
while (--t_num) {
thds.emplace_back([&]() {
auto cnt = CNT_PER_THD;
while (--cnt)
++(*p.second);
});
}
for (auto &t : thds) {
t.join();
}
const auto end = std::time(&t);
std::cout << p.first << ": " << end - start
<< ", get(): " << p.second->get() << std::endl;
}
}