当前位置: 首页 > news >正文

C++使用Thread实现子线程延时重发

需求背景

有一个需求需要往驱动传一个值,但是因为时序问题,有时传值给驱动后,设备没有亮屏,驱动无法处理。所以需要在驱动返回无法处理的状态后,等待一段时间,再进行重发。因为无法使用C++20的jthread来对线程的生命周期进行自动管理,同时传值操作在主线程,不能被阻塞,所以不能使用join()来管理thread线程的生命周期。而传值操作随时可能会被调用,甚至是连续的,所以在线程进行延时重发时,需要停止正在执行的操作,发送最新的值。

功能实现

.h

#include <atomic>class ThreadClass
{
public:ThreadClass();int setValue(int value);void changeDeviceState(bool state);private:void startThread();void updateThread();void stopThread();void runFunction();void delayTimer(int time);int sendValueToDrive(int value); // unnecessary. Analog value transfer to drive.int mCurrentValue{ -1 }; // The value to be passed.int mRetryTimes{ 0 }; // Record the number of retries.bool mIsSendValueSeccess{ false }; // Record whether the sending is successful.std::atomic<bool> mDelayFlag{ false }; // Flag indicating whether to wait for a delay.std::atomic<bool> mThreadRunningFlag{ false }; // Flag indicating whether the thread is running.
};

.cpp

#include <iostream>
#include <thread>
#include <chrono>
#include "ThreadClass.h"const int MAX_RETRY_TIMES = 5;
const int RETRY_INTERVAL_TIME = 200; // 200ms
const int DELAY_INTERVAL_TIME = 20; // 20msThreadClass::ThreadClass(){}/*** Receive the value that needs to be passed to the driver.* Calling conditions: The value passed is inconsistent with the last one or the last pass failed.
**/
int ThreadClass::setValue(int value)
{if (value < 0) {std::cout << "value error! value = " << value  << std::endl;return -1;}if (mCurrentValue != value || !mIsSendValueSeccess) {mCurrentValue = value;if (mThreadRunningFlag.load()) {// If the thread is running, update the thread.updateThread();} else {// If the thread is not running, create a new thread.startThread();}}
}/*** Receiving device status,screen on or off.
**/
void ThreadClass::changeDeviceState(bool state) {if (!state) {// If the screen is turned off, stop the thread if it is running.if (mThreadRunningFlag.load()) {stopThread();}} else if (!mIsSendValueSeccess) {// If the screen is on, resend if the last send failed.if (!mThreadRunningFlag.load()) {startThread();} else if (mRetryTimes > 2) {// If the retry times do not exceed 2, the times will not be updated.updateThread();}}
}/*** Start the thread and use detach to manage the thread life cycle.* Monitor thread execution through atomic variables.
**/
void ThreadClass::startThread()
{mIsSendValueSeccess = false;std::thread worker([this]() { runFunction(); });worker.detach();
}/*** Update thread.* Clear the retry times.* Set the delay flag to false to end the ongoing delay waiting operation.
**/
void ThreadClass::updateThread()
{mRetryTimes = 0;mDelayFlag.store(false);
}/*** Stop thread.* Set the thread running flag to false, so that the thread ends after completing the current transmission operation.* Set the delay flag to false. If the delay is in progress, the waiting will end. If the delay has not started,* the waiting will not continue.
**/
void ThreadClass::stopThread()
{mThreadRunningFlag.store(false);mDelayFlag.store(false);
}/*** Delayed waiting implementation method.* Implementation Logic:* First calculate the end waiting time.* Determine whether to wait by checking that the current time is less than the end time and the delay flag is true.* If you need to wait for 200ms, after each 20ms of sleep, determine whether you need to continue waiting.* (Waiting time and sleep time are customizable.)* If the remaining waiting time is less than 20ms, use yield() to give up the CPU time slice.
**/
void ThreadClass::delayTimer(int time)
{std::chrono::milliseconds offset(time);auto endTime = std::chrono::steady_clock::now() + offset;while (std::chrono::steady_clock::now() < endTime && mDelayFlag.load()) {auto remaining = endTime - std::chrono::steady_clock::now();if (remaining > std::chrono::milliseconds(DELAY_INTERVAL_TIME)) {std::this_thread::sleep_for(std::chrono::milliseconds(DELAY_INTERVAL_TIME));} else {while (std::chrono::steady_clock::now() < endTime && mDelayFlag.load()) {std::this_thread::yield();}break;}}
}/*** Thread execution method.* Set the flag position of whether the thread is executing to true,* and use it as the judgment condition of while to start the loop to pass the value to the driver* * If the sending is successful, this exits the while loop and ends the current thread.* If the retry times reaches 5 times, this exits the while loop and ends the current thread.* If the transmission fails and the retry times are less than 5 times,* the value will be transmitted to the driver again after a delay of 200ms.
**/
void ThreadClass::runFunction()
{std::cout << "The thread starts executing" << std::endl;mThreadRunningFlag.store(true);mRetryTimes = 0;while (mThreadRunningFlag.load()) {mRetryTimes++;int result = sendValueToDrive(mCurrentValue);if (result != -1) {std::cout << "send value to drive successed!" << std::endl;mIsSendValueSeccess = true;break;}else {std::cout << "send value to drive failed! retry times = " << mRetryTimes << std::endl;}if (mRetryTimes >= MAX_RETRY_TIMES) {std::cout << "send value to drive failed! because of max retry times." << std::endl;mIsSendValueSeccess = false;break;}if (!mDelayFlag.load()) {mDelayFlag.store(true);}if (mRetryTimes < MAX_RETRY_TIMES) {delayTimer(RETRY_INTERVAL_TIME);} else {break;}}mThreadRunningFlag.store(false);std::cout << "Thread execution completed" << std::endl;
}int ThreadClass::sendValueToDrive(int value)
{std::cout << "value = " << value << std::endl;return -1;
}

执行结果

调用代码

#include <iostream>
#include <thread>
#include <chrono>
#include "ThreadClass.h"int main()
{std::cout << "beginning" << std::endl;ThreadClass threadClass;std::cout << "set value = 1, start thread" << std::endl;threadClass.setValue(1);std::this_thread::sleep_for(std::chrono::milliseconds(500));std::cout << "set value = 0, update thread" << std::endl;threadClass.setValue(0);std::this_thread::sleep_for(std::chrono::milliseconds(400));// Figure 1 calls the changeDeviceState method, while Figure 2 does not call the changeDeviceState methodstd::cout << "set device state = false, stop thread" << std::endl;threadClass.changeDeviceState(false);std::this_thread::sleep_for(std::chrono::seconds(3));std::cout << "ending" << std::endl;}

代码输出

  • 图1
    在这里插入图片描述
  • 图2
    在这里插入图片描述

写在最后

以上代码示例经过简化。可以通过更多判断以及加锁等方式确保性能。

http://www.xdnf.cn/news/1114327.html

相关文章:

  • 语言模型常用的激活函数(Sigmoid ,GeLU ,SwiGLU,GLU,SiLU,Swish)
  • 【论文阅读】基于注意力机制的冥想脑电分类识别研究(2025)
  • LeetCode第 458 场周赛题解
  • 字符串问题(哈希表解决)
  • 【论文阅读】Think Only When You Need with Large Hybrid-Reasoning Models
  • 【源力觉醒 创作者计划】文心开源大模型ERNIE-4.5私有化部署保姆级教程与多功能界面窗口部署
  • 编译器优化——LLVM IR,零基础入门
  • 我做了一个windows端口占用查看跟释放工具
  • Spring AI 项目实战(十六):Spring + AI + 通义万相图像生成工具全栈项目实战(附完整源码)
  • linux-shell脚本
  • SpringCloud云间剑歌 第四章:藏经阁与信鸽传书
  • 打造你的专属智能生活:鸿蒙系统自定义场景开发全流程详解
  • package.json 与 package-lock.json
  • Redis缓存设计与性能优化指南
  • Web攻防-PHP反序列化原生内置类Exception类SoapClient类SimpleXMLElement
  • 分类问题-机器学习
  • 011_视觉能力与图像处理
  • 力扣面试150题--单词搜索
  • MySQL 分表功能应用场景实现全方位详解与示例
  • Flink学习笔记:整体架构
  • Docker(02) Docker-Compose、Dockerfile镜像构建、Portainer
  • 13. Flink 高可用机制简述(Standalone 模式)
  • 14.ResourceMangaer启动解析
  • 鸿蒙项目构建配置
  • LabVIEW智能避障小车
  • Http与Https区别和联系
  • [NCTF2019]Fake XML cookbook
  • 六、深度学习——NLP
  • Redis 基础详细介绍(Redis简单介绍,命令行客户端,Redis 命令,Java客户端)
  • 编程与数学 03-001 计算机组成原理 04_非数值数据表示与校验码