167 lines
5.2 KiB
Plaintext
167 lines
5.2 KiB
Plaintext
#include "mix_cc/exception.h"
|
|
#include <atomic>
|
|
#include <chrono>
|
|
#include <eqpalg/gb_item_memory.h>
|
|
#include <eqpalg/table_struct/t_rule_cfg.h>
|
|
#include <mix_cc/sql.h>
|
|
#include <mix_cc/sql/database/db2_t.h>
|
|
#include <mutex>
|
|
#include <shared_mutex>
|
|
#include <thread>
|
|
#include <tuple>
|
|
#include <vector>
|
|
|
|
namespace {
|
|
// 双缓冲区结构
|
|
struct DoubleBufferMaps {
|
|
std::unordered_map<std::string, double> read_map; // 读取用的map
|
|
std::unordered_map<std::string, double> write_map; // 写入用的map
|
|
// std::atomic<bool> swapping{false}; // 交换标志,防止重复交换
|
|
|
|
// 交换缓冲区
|
|
void swap_buffers() {
|
|
// swapping.store(true, std::memory_order_acquire);
|
|
std::swap(read_map, write_map);
|
|
// swapping.store(false, std::memory_order_release);
|
|
}
|
|
|
|
// 安全获取当前写入map的引用
|
|
std::unordered_map<std::string, double> &get_write_map() {
|
|
// 等待交换完成
|
|
// while (swapping.load(std::memory_order_acquire)) {
|
|
// std::this_thread::yield();
|
|
// }
|
|
return write_map;
|
|
}
|
|
};
|
|
|
|
DoubleBufferMaps buffer_maps; // 双缓冲区实例
|
|
std::shared_mutex buffer_mutex; // 保护缓冲区交换的互斥锁
|
|
} // namespace
|
|
|
|
// 在类外定义并初始化静态成员变量(必须)
|
|
int GlobaltemSharedMemory::instanceCount = 0;
|
|
|
|
int GlobaltemSharedMemory::get_data_size() { return data_size_; }
|
|
|
|
int GlobaltemSharedMemory::get_instanceCount() { return instanceCount; }
|
|
|
|
GlobaltemSharedMemory::GlobaltemSharedMemory() {
|
|
++instanceCount;
|
|
logger_ = std::make_unique<LOG>("GlobaltemSharedMemory");
|
|
logger_->Debug() << "GlobaltemSharedMemory::GlobaltemSharedMemory()" << endl;
|
|
}
|
|
|
|
// 获取指定tag点数据 - 无锁读取
|
|
double GlobaltemSharedMemory::operator[](std::string tag_name) {
|
|
// 直接读取前端缓冲区,无需加锁
|
|
const auto &read_map = buffer_maps.read_map;
|
|
auto it = read_map.find(tag_name);
|
|
if (it != read_map.end()) {
|
|
return it->second;
|
|
}
|
|
return 0.0; // 或者返回默认值
|
|
}
|
|
|
|
// 检查tag点是否存在 - 无锁读取
|
|
// bool GlobaltemSharedMemory::find_tag(std::string tag_name) {
|
|
// const auto& read_map = buffer_maps.read_map;
|
|
// return (read_map.find(tag_name) != read_map.end());
|
|
// }
|
|
|
|
// 从共享内存缓存数据到写入缓冲区
|
|
int GlobaltemSharedMemory::cache_data() {
|
|
try {
|
|
// 获取写入缓冲区的引用
|
|
auto &write_map = buffer_maps.get_write_map();
|
|
|
|
// 清空写入缓冲区,准备新数据
|
|
// write_map.clear();
|
|
|
|
// 为共享内存中的数据添加机组号前缀
|
|
const auto prefix = string(CMemVar::Const()->UnitNo) + "_";
|
|
for (int i = CMemVar::Const()->event_eis_start;
|
|
i <= CMemVar::Const()->event_eis_end; i++) {
|
|
if (true) {
|
|
if (m_mapfix.find(i) == m_mapfix.end()) {
|
|
m_mapfix.insert(
|
|
make_pair(i, new CMemFix<PLC_DATA>(std::to_string(i))));
|
|
}
|
|
|
|
PLC_DATA *pdata = m_mapfix[i]->getCur();
|
|
if (pdata == nullptr) {
|
|
return -1 * i;
|
|
}
|
|
|
|
binary_tele.ReBuild(i, (char *)(pdata));
|
|
const auto size = binary_tele.size();
|
|
for (int j = 0; j < size; j++) {
|
|
float value = binary_tele[j];
|
|
std::string name_without_plant_code = binary_tele[j].item;
|
|
// 添加前缀
|
|
auto item_name = prefix + name_without_plant_code;
|
|
write_map[item_name] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 数据准备完成,交换缓冲区
|
|
{
|
|
std::unique_lock<std::shared_mutex> lock(buffer_mutex);
|
|
buffer_maps.swap_buffers();
|
|
}
|
|
data_size_ = buffer_maps.read_map.size();
|
|
// logger_->Debug() << "缓冲区交换完成,读取缓冲区大小: "
|
|
// << buffer_maps.read_map.size() << endl;
|
|
|
|
} catch (const std::exception &e) {
|
|
std::throw_with_nested(
|
|
mix_cc::Exception(-1, "shared mem load error", BOOST_CURRENT_LOCATION));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//获取数据JSON表示 - 无锁读取
|
|
std::string GlobaltemSharedMemory::get_data_json() {
|
|
mix_cc::json js1;
|
|
try {
|
|
const auto &read_map = buffer_maps.read_map;
|
|
if (!read_map.empty()) {
|
|
js1 = read_map;
|
|
return js1.dump();
|
|
} else {
|
|
return "empty";
|
|
}
|
|
} catch (std::exception &e) {
|
|
return "ERROR";
|
|
}
|
|
}
|
|
|
|
// 获取缓冲区状态信息(调试用)
|
|
// std::string GlobaltemSharedMemory::get_buffer_status() {
|
|
// mix_cc::json status;
|
|
// status["read_buffer_size"] = buffer_maps.read_map.size();
|
|
// status["write_buffer_size"] = buffer_maps.write_map.size();
|
|
// status["is_swapping"] = buffer_maps.swapping.load();
|
|
// return status.dump();
|
|
// }
|
|
|
|
// // 线程安全的单个数据更新(如果需要实时更新单个值)
|
|
// void GlobaltemSharedMemory::update_single_value(const std::string& tag_name,
|
|
// double value) {
|
|
// // 获取写入缓冲区的引用
|
|
// auto& write_map = buffer_maps.get_write_map();
|
|
|
|
// // 更新写入缓冲区
|
|
// write_map[tag_name] = value;
|
|
|
|
// // 可以选择立即交换或者等待批量更新
|
|
// // 对于实时性要求高的场景,可以在这里调用交换
|
|
// }
|
|
|
|
// // 手动触发缓冲区交换(用于特殊场景)
|
|
// void GlobaltemSharedMemory::manual_swap_buffers() {
|
|
// std::unique_lock<std::shared_mutex> lock(buffer_mutex);
|
|
// buffer_maps.swap_buffers();
|
|
// logger_->Debug() << "手动交换缓冲区完成" << endl;
|
|
// } |