记忆要点
1.初始化内存
// 初始化共享内存(Linux/macOS需显式设置共享键) 17 sharedMem.setKey("Global/MyAppData"); 18 sharedMem.setNativeKey("/shm_myappdata"); // 兼容不同OS
2 创建内存
if (!sharedMem.isAttached())
sharedMem.create(sizeof(SharedData));
3. 写入内存
// 加锁写入
if (sharedMem.lock()) {
SharedData *data = static_cast<SharedData*>(sharedMem.data());
// 更新流水号(循环计数)
data->sequence = (data->sequence + 1) % 65536;
data->timestamp = QDateTime::currentMSecsSinceEpoch();
sharedMem.unlock();
}
4.读取内存
if (sharedMem.attach()) {
if (sharedMem.lock()) {
SharedData *data = static_cast<SharedData*>(sharedMem.data());
在Qt中实现跨进程数据交换与监控重启机制,可通过以下方案实现。以下代码示例展示A进程(生产者)和B进程(消费者)的协同逻辑,重点解决共享内存同步、数据循环计数、进程健康监测及自动重启四大核心问题:
方案架构设计
- 数据结构设计:采用
SharedData结构体封装流水号和校验字段,确保数据完整性 - 同步机制:使用QSharedMemory内置锁实现原子操作,避免竞态条件
- 健康监测:B进程采用双缓冲区+时间戳机制,精确检测数据更新状态
- 进程重启:通过QProcess启动备用进程实现故障转移
A进程代码实现(生产者)
cpp
// A进程主函数
#include <QCoreApplication>
#include <QSharedMemory>
#include <QTimer>
#include <QDateTime>
struct SharedData {
quint16 sequence; // 循环计数器(0-65535)
quint64 timestamp; // 数据写入时间戳
char reserved[48]; // 预留扩展字段
};
class Producer {
public:
Producer() {
// 初始化共享内存(Linux/macOS需显式设置共享键)
sharedMem.setKey("Global/MyAppData");
sharedMem.setNativeKey("/shm_myappdata"); // 兼容不同OS
// 定时写入数据
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &Producer::writeData);
timer->start(1000); // 1秒周期写入
}
private:
void writeData() {
if (!sharedMem.isAttached())
sharedMem.create(sizeof(SharedData));
// 加锁写入
if (sharedMem.lock()) {
SharedData *data = static_cast<SharedData*>(sharedMem.data());
// 更新流水号(循环计数)
data->sequence = (data->sequence + 1) % 65536;
data->timestamp = QDateTime::currentMSecsSinceEpoch();
sharedMem.unlock();
}
}
QSharedMemory sharedMem;
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
Producer producer;
return a.exec();
}
B进程代码实现(消费者+监控)
cpp
// B进程主函数
#include <QCoreApplication>
#include <QSharedMemory>
#include <QTimer>
#include <QProcess>
#include <QFile>
class Monitor {
public:
Monitor() : restartCount(0) {
sharedMem.setKey("Global/MyAppData");
sharedMem.setNativeKey("/shm_myappdata");
// 每500ms检查数据
QTimer *checkTimer = new QTimer(this);
connect(checkTimer, &QTimer::timeout, this, &Monitor::checkData);
checkTimer->start(500);
}
private:
void checkData() {
if (sharedMem.attach()) {
if (sharedMem.lock()) {
SharedData *data = static_cast<SharedData*>(sharedMem.data());
// 首次检测初始化
if (lastSequence == 0xFFFF) {
lastSequence = data->sequence;
lastTimestamp = data->timestamp;
sharedMem.unlock();
return;
}
// 检查数据更新
bool dataStale = (data->sequence == lastSequence)
&& (data->timestamp == lastTimestamp);
// 更新缓存值
lastSequence = data->sequence;
lastTimestamp = data->timestamp;
sharedMem.unlock();
// 触发重启逻辑
if (dataStale && ++staleCount >= 4) {
restartProducer();
}
}
}
}
void restartProducer() {
// 记录重启次数
QFile logFile("restart.log");
logFile.open(QIODevice::Append);
logFile.write(("Restart at: " + QDateTime::currentDateTime().toString() + "\n").toUtf8());
// 启动新进程
QProcess::startDetached("A进程路径", QStringList());
// 限制重启次数
if (restartCount++ > 5) {
qFatal("Excessive restarts, terminating.");
}
}
QSharedMemory sharedMem;
quint16 lastSequence = 0xFFFF; // 初始无效值
quint64 lastTimestamp = 0;
int staleCount = 0;
int restartCount;
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
Monitor monitor;
return a.exec();
}
关键技术点说明
- 跨平台兼容性
- Windows使用全局共享内存键
Global\MyAppData - Linux/macOS使用POSIX共享内存
/shm_myappdata - 需确保两进程使用相同的标识符
- Windows使用全局共享内存键
- 数据同步保障
- 使用
lock()和unlock()进行原子操作 - 时间戳字段验证数据新鲜度
- 双缓冲区机制避免撕裂现象
- 使用
- 健康监测算法
- 连续4次检测到数据未更新才触发重启
- 500ms采样间隔平衡性能与实时性
- 重启次数限制防止雪崩效应
- 故障恢复机制
- 重启日志记录便于故障诊断
- 进程启动使用
startDetached避免僵尸进程 - 最大重启次数限制保障系统稳定性
部署注意事项
-
编译配置
- 需在.pro文件中启用
shared选项
makefileQT += core CONFIG += shared - 需在.pro文件中启用
-
权限设置
- Linux需确保用户有
/dev/shm访问权限 - macOS需配置沙盒权限
- Linux需确保用户有
-
调试建议
- 使用
strace或dtrace跟踪共享内存操作 - 通过
QSharedMemory::size()验证内存映射状态
- 使用
该方案实现了生产者-消费者模式下的进程间通信与健康监测,通过循环计数和时间戳机制保障数据一致性,结合进程重启策略实现故障恢复,适用于需要高可用性的工业控制、实时数据处理等场景。
1301

被折叠的 条评论
为什么被折叠?



