
回复
哈喽!我是小L,那个在鸿蒙进程间「搬数据」的女程序员~ 你知道吗?在智能家居场景中,温湿度传感器、光照传感器、人体红外传感器可能各自运行在独立进程,如何让它们的数据像「流水线」一样实时汇聚到主进程?今天就来拆解如何用IPC+共享内存打造「零延迟、高可靠」的多进程数据采集系统~
角色 | 职责描述 | 技术实现 |
---|---|---|
采集进程 | 单进程单传感器,负责数据采集 | IPC客户端(Proxy)+ 异步线程 |
整合进程 | 汇总所有传感器数据,实时处理 | IPC服务端(Stub)+ 共享内存 |
通信桥梁 | 进程间数据传输与状态监控 | IPC Kit + DeathRecipient |
graph TD
A[采集进程] -->|数据帧格式| B[整合进程]
B -->|ACK应答| A
数据帧格式: [魔法数(4B)] [传感器ID(2B)] [数据长度(2B)] [有效载荷(NB)] [CRC32(4B)]
class SensorCollector {
public:
void StartCollecting(OHIPCRemoteProxy* proxy) {
isRunning_ = true;
collectorThread_ = std::thread([this, proxy]() {
while (isRunning_) {
int data = ReadSensorData(); // 读取传感器原始数据
SendDataAsynchronously(proxy, data); // 异步发送
std::this_thread::sleep_for(std::chrono::milliseconds(10)); // 10ms采集间隔
}
});
}
private:
void SendDataAsynchronously(OHIPCRemoteProxy* proxy, int data) {
OHIPCParcel* dataParcel = OH_IPCParcel_Create();
if (!dataParcel) return;
// 打包数据帧
OH_IPCParcel_WriteInt32(dataParcel, MAGIC_NUMBER); // 魔法数
OH_IPCParcel_WriteInt16(dataParcel, SENSOR_ID_TEMPERATURE); // 传感器ID
OH_IPCParcel_WriteInt32(dataParcel, data); // 有效载荷
OH_IPC_MessageOption option = {OH_IPC_REQUEST_MODE_ASYNC, 0};
OHIPCRemoteProxy_SendRequest(proxy, REQUEST_CODE_SENSOR_DATA, dataParcel, nullptr, &option);
OH_IPCParcel_Destroy(dataParcel);
}
std::thread collectorThread_;
bool isRunning_ = false;
};
// 缓存100条数据后批量发送
std::queue<int> dataBuffer_;
std::mutex bufferMutex_;
void BufferData(int data) {
std::lock_guard<std::mutex> lock(bufferMutex_);
dataBuffer_.push(data);
if (dataBuffer_.size() >= 100) {
SendBatchData(); // 触发批量发送
}
}
void SendBatchData() {
std::vector<int> batchData;
{
std::lock_guard<std::mutex> lock(bufferMutex_);
while (!dataBuffer_.empty()) {
batchData.push_back(dataBuffer_.front());
dataBuffer_.pop();
}
}
// 打包批量数据(使用flatbuffer序列化)
flatbuffers::FlatBufferBuilder fbb;
auto fbData = CreateSensorDataBatch(fbb, SENSOR_ID_HUMIDITY, batchData.data(), batchData.size());
fbb.Finish(fbData);
OHIPCParcel* dataParcel = OH_IPCParcel_Create();
OH_IPCParcel_WriteBuffer(dataParcel, fbb.GetBufferPointer(), fbb.GetSize());
// 发送批量数据帧...
}
// 初始化共享内存(大小1MB)
int shmFd = shm_open("/data_shm", O_RDWR | O_CREAT, 0666);
ftruncate(shmFd, 1024 * 1024);
void* sharedMem = mmap(nullptr, 1024 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, shmFd, 0);
// 写入数据时直接操作共享内存指针
void* WriteDataToSharedMem(int sensorId, const void* data, size_t size) {
std::lock_guard<std::mutex> lock(sharedMemMutex_);
DataHeader* header = static_cast<DataHeader*>(sharedMem);
if (header->offset + size > 1024*1024) {
// 循环覆盖(或触发数据持久化)
header->offset = sizeof(DataHeader);
}
char* dataPtr = static_cast<char*>(sharedMem) + header->offset;
memcpy(dataPtr, data, size);
header->offset += size;
return dataPtr;
}
graph LR
A[IPC接收线程] --> B[数据解析线程池]
B --> C[业务处理线程]
C --> D[共享内存写入]
// IPC接收线程
void IpcReceiverThread(OHIPCRemoteStub* stub) {
while (isRunning_) {
OHIPCMessage* msg = OH_IPCRemoteStub_ReceiveMessage(stub);
if (msg->code == REQUEST_CODE_SENSOR_DATA) {
// 解包数据并放入解析队列
dataParseQueue_.push(msg->data);
}
OH_IPCMessage_Destroy(msg);
}
}
// 数据解析线程池(4个工作线程)
std::vector<std::thread> parserThreads;
for (int i=0; i<4; ++i) {
parserThreads.emplace_back([this]() {
while (isRunning_) {
OHIPCParcel* dataParcel = nullptr;
{
std::lock_guard<std::mutex> lock(queueMutex_);
if (dataParseQueue_.empty()) continue;
dataParcel = dataParseQueue_.front();
dataParseQueue_.pop();
}
ParseAndProcessData(dataParcel);
OH_IPCParcel_Destroy(dataParcel);
}
});
}
// 给每个采集进程注册死亡通知
void RegisterCollectorDeathRecipient(OHIPCRemoteProxy* proxy, int collectorId) {
OHIPCDeathRecipient recipient = {};
recipient.onRemoteDied = [this, collectorId](void* /*userData*/) {
std::lock_guard<std::mutex> lock(collectorsMutex_);
collectors_.erase(collectorId);
LogWarn("Collector %d died, restarting...", collectorId);
RestartCollectorProcess(collectorId); // 自动重启采集进程
};
OH_IPCRemoteProxy_AddDeathRecipient(proxy, &recipient);
}
// 自动重启逻辑(伪代码)
void RestartCollectorProcess(int collectorId) {
// 解析采集进程配置
CollectorConfig config = GetCollectorConfig(collectorId);
// 启动新进程
pid_t pid = fork();
if (pid == 0) {
execl(config.execPath, config.args...); // 子进程执行采集程序
}
}
// 采集进程收到SIGTERM信号处理
void HandleQuitSignal(int signum) {
isRunning_ = false;
// 等待当前数据发送完成
collectorThread_.join();
// 通知整合进程自己即将退出
OHIPCRemoteProxy_SendRequest(proxy_, REQUEST_CODE_PROCESS_QUIT, nullptr, nullptr, nullptr);
exit(0);
}
指标 | 实现效果 | 优化点 |
---|---|---|
单进程数据延迟 | <10ms | 异步通信+共享内存零拷贝 |
并发采集进程数 | 支持100+ | 线程池+连接池技术 |
内存占用 | 每个采集进程<5MB | 轻量级IPC协议+扁平数据结构 |
故障恢复时间 | <500ms | 死亡通知+预启动备用进程 |
// 共享内存访问加锁(关键代码段)
std::atomic<bool> isWriting_{false};
void SafeWriteToSharedMem(const void* data, size_t size) {
while (isWriting_.exchange(true, std::memory_order_acquire)) {
std::this_thread::yield(); // 自旋等待
}
try {
// 写入操作...
} finally {
isWriting_.store(false, std::memory_order_release);
}
}
// 在整合进程中注册SIGCHLD信号处理
void HandleChildSignal(int signum) {
while (waitpid(-1, nullptr, WNOHANG) > 0) {
LogDebug("Cleaned zombie child process");
}
}
hilog
跨进程追踪日志,关键词标注进程IDOHOS::HiviewDFX::HiLog::setLogLevel
动态调整日志级别OHOS::AppExecFwk::EventFwk
发送跨进程调试事件未来支持根据数据流量自动增减采集进程数:
graph LR
A[数据流量监测] --> B{流量>阈值?}
B -->|是| C[启动新采集进程]
B -->|否| D[关闭闲置进程]
采集进程直接在边缘设备完成数据预处理,仅向主进程传输「特征值」:
引入量子密钥分发(QKD),实现IPC通信链路的物理层安全,防止数据被窃听篡改~
稳定性 = (进程隔离性 × 通信可靠性)÷ 资源竞争度