This commit is contained in:
hukai 2025-07-22 15:16:40 +08:00
commit c9ae8bf0d9
11 changed files with 12035 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

31
CMakeLists.txt Normal file
View File

@ -0,0 +1,31 @@
cmake_minimum_required(VERSION 3.15)
#
project(shm_compare)
# C++
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
#
aux_source_directory(src SOURCES_DIR)
set(SOURCES
${SOURCES_DIR}
main.cpp
)
set(BENCHMARKS
${SOURCES_DIR}
benchmark.cpp
)
#
include_directories(include third_party)
# Google Benchmark
find_package(benchmark REQUIRED)
#
add_executable(server ${SOURCES})
add_executable(benchmark ${BENCHMARKS})
# 线
target_link_libraries(server pthread)
target_link_libraries(benchmark pthread benchmark::benchmark)

14
README.md Normal file
View File

@ -0,0 +1,14 @@
# Share memory Vs Http
## 结果
![alt text](res.png)
## 测试
```shell
cmake -B build
cmake --build build
```
开两个终端分别运行 `./build/server``./build/benchmark`

281
benchmark.cpp Normal file
View File

@ -0,0 +1,281 @@
#include <iostream>
#include <string>
#include <random>
#include <httplib.h>
#include <benchmark/benchmark.h>
#include <shm.h>
const size_t data_length = 32; // 随机数据长度
const std::string server_addr = "http://localhost:8080";
// 生成随机字符串
static std::string generate_random_string(size_t length)
{
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_int_distribution<> dis(0, sizeof(alphanum) - 2);
std::string str;
str.reserve(length);
for (size_t i = 0; i < length; ++i)
{
str += alphanum[dis(gen)];
}
return str;
}
// Http 写操作
static void HttpWrite(benchmark::State& state)
{
httplib::Client cli(server_addr);
for (auto _ : state)
{
std::string data = generate_random_string(data_length);
auto res = cli.Post("/write", data, "text/plain");
if (res && res->status == 200)
{
benchmark::DoNotOptimize(res->body);
}
else
{
std::cerr << "Write failed!" << std::endl;
}
}
}
// Http 读操作
static void HttpRead(benchmark::State& state)
{
httplib::Client cli(server_addr);
for (auto _ : state)
{
auto res = cli.Get("/read");
if (res && res->status == 200)
{
benchmark::DoNotOptimize(res->body);
}
else
{
std::cerr << "Read failed!" << std::endl;
}
}
}
static void HttpWriteRead(benchmark::State& state)
{
httplib::Client cli(server_addr);
for (auto _ : state)
{
// write
std::string data = generate_random_string(data_length);
auto write_res = cli.Post("/write", data, "text/plain");
// 写入断言
if (!write_res)
{
state.SkipWithError("Write request failed - no response");
continue;
}
assert(write_res->status == 200 && "Write operation failed");
assert(write_res->body == "OK" && "Unexpected write response");
// read
auto read_res = cli.Get("/read");
// 读取断言
if (!read_res)
{
state.SkipWithError("Read request failed - no response");
continue;
}
assert(read_res->status == 200 && "Read operation failed");
assert(read_res->body == data && "Read data doesn't match written data");
// 防止编译器优化掉结果
benchmark::DoNotOptimize(write_res);
benchmark::DoNotOptimize(read_res);
}
}
static void HttpWriteWithLock(benchmark::State& state)
{
httplib::Client cli(server_addr);
for (auto _ : state)
{
std::string data = generate_random_string(data_length);
auto res = cli.Post("/write/lock", data, "text/plain");
if (res && res->status == 200)
{
benchmark::DoNotOptimize(res->body);
}
else
{
std::cerr << "Write failed!" << std::endl;
}
}
}
// Http 读操作
static void HttpReadWithLock(benchmark::State& state)
{
httplib::Client cli(server_addr);
for (auto _ : state)
{
auto res = cli.Get("/read/lock");
if (res && res->status == 200)
{
benchmark::DoNotOptimize(res->body);
}
else
{
std::cerr << "Read failed!" << std::endl;
}
}
}
static void HttpWriteReadWithLock(benchmark::State& state)
{
httplib::Client cli(server_addr);
for (auto _ : state)
{
// write
std::string data = generate_random_string(data_length);
auto write_res = cli.Post("/write/lock", data, "text/plain");
// 写入断言
if (!write_res)
{
state.SkipWithError("Write request failed - no response");
continue;
}
assert(write_res->status == 200 && "Write operation failed");
assert(write_res->body == "OK" && "Unexpected write response");
// read
auto read_res = cli.Get("/read/lock");
// 读取断言
if (!read_res)
{
state.SkipWithError("Read request failed - no response");
continue;
}
assert(read_res->status == 200 && "Read operation failed");
assert(read_res->body == data && "Read data doesn't match written data");
// 防止编译器优化掉结果
benchmark::DoNotOptimize(write_res);
benchmark::DoNotOptimize(read_res);
}
}
// =============================================== Shm ===============================================
// Shm 写操作
static void ShmWrite(benchmark::State& state)
{
for (auto _ : state)
{
std::string data = generate_random_string(data_length);
auto res = shm_write(data);
if (res)
{
benchmark::DoNotOptimize(res);
}
else
{
std::cerr << "Write failed!" << std::endl;
}
}
}
// Shm 读操作
static void ShmRead(benchmark::State& state)
{
for (auto _ : state)
{
auto res = shm_read();
if (!res.empty())
{
benchmark::DoNotOptimize(res);
}
else
{
std::cerr << "Read failed!" << std::endl;
}
}
}
static void ShmReadWrite(benchmark::State& state)
{
for (auto _ : state)
{
// write
std::string data = generate_random_string(data_length);
auto write_res = shm_write(data);
if (write_res)
{
benchmark::DoNotOptimize(write_res);
}
else
{
std::cerr << "Write failed!" << std::endl;
}
// read
auto read_res = shm_read();
// 读取断言
if (!read_res.empty())
{
benchmark::DoNotOptimize(read_res);
}
else
{
std::cerr << "Read failed!" << std::endl;
}
assert(read_res == data && "Read data doesn't match written data");
// 防止编译器优化掉结果
benchmark::DoNotOptimize(write_res);
benchmark::DoNotOptimize(read_res);
}
}
// 注册基准测试
// HTTP 共享数据
BENCHMARK(HttpWrite);
BENCHMARK(HttpRead);
BENCHMARK(HttpWriteRead);
// HTTP 带锁共享数据
BENCHMARK(HttpWriteWithLock);
BENCHMARK(HttpReadWithLock);
BENCHMARK(HttpWriteReadWithLock);
// Shm 带锁共享数据
BENCHMARK(ShmWrite);
BENCHMARK(ShmRead);
BENCHMARK_MAIN();

3
include/http.h Normal file
View File

@ -0,0 +1,3 @@
#pragma region
void start_server();

4
include/shm.h Normal file
View File

@ -0,0 +1,4 @@
#pragma region
bool shm_write(const std::string& data);
std::string shm_read();

7
main.cpp Normal file
View File

@ -0,0 +1,7 @@
#include "http.h"
int main()
{
start_server();
return 0;
}

BIN
res.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

49
src/http.cpp Normal file
View File

@ -0,0 +1,49 @@
#include "http.h"
#include "httplib.h"
using namespace httplib;
std::string shared_data = ""; // 共享数据
std::string shared_mutex_data = ""; // 带锁共享数据
std::mutex mtx; // 互斥锁保护共享变量
// 处理写请求
void handle_write(const Request& req, Response& res)
{
shared_data = req.body;
res.set_content("OK", "text/plain");
}
// 处理读请求
void handle_read(const Request& req, Response& res)
{
res.set_content(shared_data, "text/plain");
}
void handle_write_with_lock(const Request& req, Response& res)
{
std::lock_guard<std::mutex> lock(mtx); // 加锁
shared_data = req.body;
res.set_content("OK", "text/plain");
}
void handle_read_with_lock(const Request& req, Response& res)
{
std::lock_guard<std::mutex> lock(mtx); // 加锁
res.set_content(shared_data, "text/plain");
}
void start_server()
{
Server svr;
svr.Post("/write", handle_write);
svr.Get("/read", handle_read);
svr.Post("/write/lock", handle_write_with_lock);
svr.Get("/read/lock", handle_read_with_lock);
std::cout << "Server started at http://localhost:8080" << std::endl;
svr.listen("localhost", 8080);
}

89
src/shm.cpp Normal file
View File

@ -0,0 +1,89 @@
#include <iostream>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstring>
#include <shm.h>
#define SHM_NAME "/shm"
#define SHM_SIZE 1024
bool shm_write(const std::string& data)
{
if (data.size() + sizeof(std::size_t) > SHM_SIZE)
{
std::cout << "out of size" << std::endl;
return false;
}
// 打开/创建共享内存
int fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);
if (fd == -1)
{
perror("shm_open");
return false;
}
if (ftruncate(fd, SHM_SIZE) == -1)
{
perror("ftruncate");
close(fd);
return false;
}
void* addr = mmap(nullptr, SHM_SIZE, PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
{
perror("mmap");
close(fd);
return false;
}
std::byte* ptr = static_cast<std::byte*>(addr);
std::size_t len = data.size();
std::memcpy(ptr, &len, sizeof(len));
std::memcpy(ptr + sizeof(len), data.data(), len);
munmap(addr, SHM_SIZE);
close(fd);
return true;
}
std::string shm_read()
{
int fd = shm_open(SHM_NAME, O_RDONLY, 0666);
if (fd == -1)
{
perror("shm_open failed for receive()");
return "";
}
void* addr = mmap(nullptr, SHM_SIZE, PROT_READ, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
{
perror("mmap failed in receive()");
close(fd);
return "";
}
std::byte* ptr = static_cast<std::byte*>(addr);
std::size_t len = 0;
std::memcpy(&len, ptr, sizeof(len)); // 读取前缀长度
if (len > SHM_SIZE - sizeof(len))
{
munmap(addr, SHM_SIZE);
perror("data length exceeds shared memory size");
close(fd);
return "";
}
std::string result(reinterpret_cast<char*>(ptr + sizeof(len)), len);
munmap(addr, SHM_SIZE);
close(fd);
return result;
}

11556
third_party/httplib.h vendored Normal file

File diff suppressed because it is too large Load Diff