C++后台进程

C++定时器实现定时任务 1、单次定时任务实现  boost的asio库里有几个定时器,老的有deadline_timer, 还有三个可配合 C++11 的 chrono 使用的high_resolution_timer、steady_timer和system_timer。deadline_timer是asio早期版本提供的定时器,使用boost.date_time库提供时间支持,deadline_timer会被逐渐淘汰。 仅仅固定时间后去执行某任务,可以使用boost中的asio库提供了steady_ti... 阅读详情

第一步:理解 “后台线程” 的本质

在 C++ 中,“后台线程” 本质是 “分离线程(detached thread)”,它的特点是:

  • 启动后独立运行,不需要主线程等待它结束。
  • 线程结束后,系统会自动回收它的资源(不需要主线程调用 join())。
  • 适合执行 “后台任务”,比如日志记录、定时检查、数据同步等。

与之对应的是 “可连接线程(joinable thread)”,这种线程必须让主线程用 join() 等待它结束,否则程序会崩溃(资源泄露)。

第二步:准备基础环境

要使用 C++ 的线程库,需要:

  1. 编译器支持 C++11 及以上标准(现在主流编译器都支持,比如 GCC、Clang、MSVC)。
  2. 包含头文件 <thread>(线程核心功能)。
  3. 编译时可能需要链接线程库(比如 GCC 要加 -pthread 参数)。

第三步:创建一个最简单的线程

先从 “可连接线程” 开始,理解线程的基本用法,再过渡到后台线程。

代码示例(步骤 1):创建线程并执行函数

cpp

运行

#include <iostream>
#include <thread>  // 线程库头文件

// 线程要执行的函数(后台任务)
void print_message() {
    std::cout << "这是线程执行的内容\n";
}

int main() {
    // 1. 创建线程对象,绑定要执行的函数 print_message
    std::thread my_thread(print_message);

    // 2. 必须等待线程结束(否则程序会崩溃)
    // 原因:my_thread 是“可连接线程”,如果不调用 join(),线程对象销毁时会触发异常
    my_thread.join();

    std::cout << "主线程执行结束\n";
    return 0;
}

编译运行(以 GCC 为例):

bash

g++ -std=c++11 thread_demo.cpp -o thread_demo -pthread
./thread_demo

输出结果:

plaintext

这是线程执行的内容
主线程执行结束

关键解释:

  • std::thread my_thread(print_message):创建线程对象 my_thread,并让它执行 print_message 函数。
  • my_thread.join():主线程会暂停,等待 my_thread 执行完毕后再继续。这一步是必须的,否则 my_thread 销毁时会调用 std::terminate() 终止程序。

第四步:将线程转为 “后台线程”(分离线程)

要让线程成为后台线程,只需调用 detach() 方法,而不是 join()。

代码示例(步骤 2):分离线程,使其成为后台线程

cpp

运行

#include <iostream>
#include <thread>

void print_message() {
    std::cout << "这是后台线程执行的内容\n";
}

int main() {
    // 1. 创建线程对象
    std::thread my_thread(print_message);

    // 2. 分离线程:使其成为后台线程
    // 调用 detach() 后,线程会独立运行,主线程无需等待
    my_thread.detach();

    // 注意:主线程如果退出太快,可能看不到后台线程的输出
    // 这里加个小延迟,确保后台线程有时间执行
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "主线程执行结束\n";
    return 0;
}

输出结果:

plaintext

这是后台线程执行的内容
主线程执行结束

关键解释:

  • my_thread.detach():将线程分离,使其成为后台线程。此时线程的生命周期与主线程独立,主线程无需等待它。
  • std::this_thread::sleep_for(...):让主线程休眠 1 秒。如果不加这行,主线程可能在后台线程执行前就结束了,导致后台线程被强制终止(看不到输出)。

第五步:让后台线程执行 “循环任务”

实际场景中,后台线程通常需要持续执行任务(比如定时输出日志)。我们可以用一个循环让线程一直运行,直到收到退出信号。

代码示例(步骤 3):后台线程执行循环任务

cpp

运行

#include <iostream>
#include <thread>
#include <chrono>  // 用于时间相关操作(休眠)

// 后台线程的循环任务
void background_work() {
    // 循环执行10次(模拟持续任务)
    for (int i = 0; i < 10; ++i) {
        std::cout << "后台线程工作中... 第" << i+1 << "次\n";
        // 每次工作后休眠1秒(模拟任务间隔)
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
    std::cout << "后台线程任务完成\n";
}

int main() {
    std::thread bg_thread(background_work);  // 创建线程
    bg_thread.detach();  // 转为后台线程

    // 主线程休眠5秒(此时后台线程会继续运行)
    std::cout << "主线程休眠5秒...\n";
    std::this_thread::sleep_for(std::chrono::seconds(5));

    std::cout << "主线程执行结束\n";
    // 注意:主线程结束后,后台线程可能还在运行,但会被系统强制终止
    return 0;
}

输出结果(部分):

plaintext

主线程休眠5秒...
后台线程工作中... 第1次
后台线程工作中... 第2次
后台线程工作中... 第3次
后台线程工作中... 第4次
后台线程工作中... 第5次
主线程执行结束

关键解释:

  • 后台线程在 background_work 中用循环执行 10 次任务,每次间隔 1 秒。
  • 主线程只休眠 5 秒就结束了,此时后台线程只执行了 5 次,剩下的任务会被系统强制终止(因为进程退出后所有线程都会结束)。

第六步:优雅地停止后台线程(线程间通信)

上面的例子中,主线程结束会强制终止后台线程,可能导致后台线程的清理工作(比如关闭文件、释放资源)无法完成。我们需要一种方式让主线程 “通知” 后台线程退出,实现 “优雅停止”。

核心思路: 用一个共享的 “退出标志”(原子变量,确保线程安全),后台线程定期检查这个标志,当标志为 true 时主动退出。

代码示例(步骤 4):用原子变量控制后台线程退出

cpp

运行

#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>  // 原子变量头文件,用于线程安全的变量访问

// 原子变量:退出标志(线程间安全读写,无需加锁)
std::atomic<bool> should_exit(false);

// 后台线程任务:循环执行,直到收到退出标志
void background_work() {
    int count = 0;
    while (!should_exit) {  // 检查退出标志
        std::cout << "后台线程工作中... 第" << ++count << "次\n";
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
    // 退出前的清理工作
    std::cout << "后台线程收到退出信号,开始清理资源...\n";
    std::cout << "后台线程退出\n";
}

int main() {
    std::thread bg_thread(background_work);
    bg_thread.detach();

    // 主线程运行3秒后,通知后台线程退出
    std::cout << "主线程等待3秒后通知后台线程退出...\n";
    std::this_thread::sleep_for(std::chrono::seconds(3));

    // 发送退出信号
    should_exit = true;

    // 等待后台线程完成清理(给1秒时间)
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "主线程退出\n";
    return 0;
}

输出结果:

plaintext

主线程等待3秒后通知后台线程退出...
后台线程工作中... 第1次
后台线程工作中... 第2次
后台线程工作中... 第3次
后台线程收到退出信号,开始清理资源...
后台线程退出
主线程退出

关键解释:

  • std::atomic<bool> should_exit(false):原子变量,保证多个线程对它的读写操作是 “原子的”(不会出现数据竞争)。如果用普通 bool,多线程读写可能导致未定义行为。
  • 后台线程在循环中通过 !should_exit 检查是否需要退出,当主线程将 should_exit 设为 true 时,后台线程会退出循环并执行清理工作。
  • 主线程最后休眠 1 秒,是为了给后台线程足够的时间完成清理(实际开发中可根据任务耗时调整)。

第七步:处理线程安全的输出(避免混乱)

多个线程同时使用 std::cout 输出时,可能会导致内容混乱(比如两个线程的输出穿插在一起)。需要用 互斥锁(mutex) 保证同一时间只有一个线程能输出。

代码示例(步骤 5):用互斥锁保证输出线程安全

cpp

运行

#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
#include <mutex>  // 互斥锁头文件

std::atomic<bool> should_exit(false);
std::mutex cout_mutex;  // 用于保护 std::cout 的互斥锁

void background_work() {
    int count = 0;
    while (!should_exit) {
        // 加锁:确保同一时间只有一个线程使用 cout
        std::lock_guard<std::mutex> lock(cout_mutex);
        std::cout << "后台线程工作中... 第" << ++count << "次\n";
        
        // 解锁:lock_guard 会在离开作用域时自动解锁(即使发生异常)
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    // 清理工作也需要加锁输出
    std::lock_guard<std::mutex> lock(cout_mutex);
    std::cout << "后台线程退出\n";
}

int main() {
    std::thread bg_thread(background_work);
    bg_thread.detach();

    // 主线程也输出一些内容,测试锁的效果
    for (int i = 0; i < 2; ++i) {
        std::lock_guard<std::mutex> lock(cout_mutex);
        std::cout << "主线程输出... 第" << i+1 << "次\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(500));  // 休眠500毫秒
    }

    // 通知后台线程退出
    should_exit = true;
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::lock_guard<std::mutex> lock(cout_mutex);
    std::cout << "主线程退出\n";
    return 0;
}

输出结果(有序,无混乱):

plaintext

后台线程工作中... 第1次
主线程输出... 第1次
后台线程工作中... 第2次
主线程输出... 第2次
后台线程工作中... 第3次
后台线程退出
主线程退出

关键解释:

  • std::mutex cout_mutex:互斥锁,像一把 “钥匙”,同一时间只有一个线程能拿到钥匙(加锁)。
  • std::lock_guard<std::mutex> lock(cout_mutex):自动加锁 / 解锁工具。创建 lock 时会给 cout_mutex 加锁,lock 销毁时(离开作用域)会自动解锁,避免忘记解锁导致死锁。
  • 加锁后,std::cout 的输出会被 “保护”,多个线程的输出不会穿插混乱。

总结:后台线程的核心要点

  1. 创建与分离:用 std::thread 创建线程,调用 detach() 使其成为后台线程(无需 join())。
  2. 生命周期:后台线程随进程退出而终止,需确保主线程退出前给后台线程足够的清理时间。
  3. 线程安全:
    • 用 std::atomic 处理简单的共享变量(如退出标志)。
    • 用 std::mutex + std::lock_guard 处理复杂的共享资源(如输出、数据结构)。
  4. 优雅退出:通过共享标志让后台线程主动退出,避免被强制终止。
C++后台开发面试题总结(涉及C++基础、多线程多进程、网络编程等) C++后台开发面试题总结(涉及C++基础知识、多线程多进程、TCP/IP网络编程、Linux操作、数据结构与算法) 因巩固知识体系,面试,梳理以往看到过的知识点,故总结如下相关题目,题目答案请自行google baidu,这里只提供题目。 一、C++基础知识面试题总结 1、多态的实现 2、说说C/C++的区别 3、const关键字 4、说说malloc/free 和 new/delete区别 5、指针和引用的区别 6、C++中堆和栈的区别 7、关键字static 8、在C++程序中调用被 阅读详情

相关推荐

告别Visual C++ Runtime Library断言失败弹窗:从Adobe后台进程切入的根治指南

本文详细解析了Visual C++ Runtime Library断言失败弹窗的根治方法,特别针对Adobe后台进程引发的常见问题。通过任务管理器定位问题进程、安全移除方案及预防措施,帮助用户彻底解决这一困扰。文章特别强调了Acrotray等Adobe相关进程的排查技巧,提供了临时和永久两种解决方案。

weixin_30298497的博客 232

c++简单定时器实现

c++简单定时器实现。

yuanshenqiang的博客 4513

C++采用Daemon进行后台程序的部署

通过调用fork()函数创建一个子进程。这将产生一个新的进程,该进程是原始进程的副本。对于子进程,fork()返回0,对于父进程,fork()返回子进程的进程id。在C++中,如果要让一个程序一直在后台运行并且和终端会话分离,我们可以将其作为守护进程运行,以下是创建C++守护进程的一般步骤。在子进程中,调用setsid()函数创建一个新的会话,这将使得子进程成为新会话的领导进程,并且摆脱原来的控制终端。使用chdir()函数来创建一个新的会话,这将使得子进程成为新会话的领导进程,同时摆脱原来的控制终端。

qq_43398345的博客 923

C++ 实现定时器的两种方法(线程定时和时间轮算法修改版)

定时器要求在固定的时间异步执行一个操作,比如boost库中的boost::asio::deadline_timer,以及MFC中的定时器。可以利用c++11的thread, mutex, condition_variable 来实现一个定时器。使用static以免被析构,可在cpp类外全局声明,第一个参数为任务容量最大数量,第二个参数为定时判断的毫秒数即最低检测时间单位。使用C++11中的thread, mutex, condition_variable来实现一个定时器。在要使用的地方,启动并添加任务。

Leckun的专栏 1万+

C++实现隐藏控制台应用程序后台运行

总结起来,通过使用Windows API函数来隐藏控制台窗口,我们可以实现C++控制台应用程序在后台运行的效果。同时,通过重定向输出或禁用输出,我们可以控制控制台应用程序的输出行为。在C++中,我们可以使用一些技巧来隐藏控制台应用程序的窗口,并使其在后台运行,而不显示在用户的桌面上。这在某些情况下是有用的,例如当我们希望在后台执行一些任务而不干扰用户的操作。需要注意的是,由于这是一个控制台应用程序,它仍然会在后台运行并输出到控制台。如果你不想看到输出,你可以将输出重定向到一个文件或者禁用输出。

DplaAnaconda的博客 1489

VC Spyglass:Lint实战指南之TCL脚本自动化解析

本文详细介绍了如何利用TCL脚本实现VC Spyglass Lint检查的自动化流程。通过实战指南,从基础脚本编写到高级参数化技巧,帮助数字IC设计工程师摆脱手动操作,提升验证效率,并实现与CI/CD流程的集成。

h3i4j的博客 796

C++:详解C++11 线程(一):实现简易定时器的示例代码

C++:详解C++11 线程(一):实现简易定时器的示例代码

C++ JAVA的专栏 2200

Zynq 【SDK裸机开发之PS】——DDR的内存分配使用详解

Zynq如果跑操作系统的话,内存管理的工作都会交给系统来操作,但是如果是裸机的话,则需要自己对DDR3的内存进行管理。

shizhibuyi1234的博客 7376

如何让你的cpp服务器在SSH 断开后使进程仍在后台运行

如何让你的cpp服务器在SSH 断开后使进程仍在后台运行

敖丙007的博客 1099

ISP Tuning实战指南:从基础到高级的色彩与亮度优化

本文详细介绍了ISP Tuning的基础概念与高级调优技术,包括黑电平校正(BLC)、自动白平衡(AWB)、色彩校正矩阵(CCM)和Gamma曲线调整等核心算法。通过实战案例和调试技巧,帮助工程师提升摄像头成像质量,解决高光过曝、暗部噪点等常见问题,适用于智能门铃、车载摄像头等多种场景。

weixin_30879169的博客 108

基于立创EDA的IP5389BZ+IP6829 100W有线15W无线带屏充电宝DIY全流程解析

本文详细解析了基于立创EDA平台,采用IP5389BZ和IP6829芯片DIY一款100W有线快充、15W无线充电并带显示屏的移动电源的全过程。内容涵盖核心功能规划、硬件选型、电路设计、PCB布局、焊接组装、分步调试以及软件逻辑,为电子爱好者提供了一份从原理到实践的完整指南,并重点强调了电池安全与IP6829供电电压等关键注意事项。

weixin_34374684的博客 306

c++ 遍历后台进程,并关闭相关进程

123456789101112131415161718                                关闭后台QQint CMainFrame::AutoSsrStop()             //*遍历后台进程,关闭相关进程。{ char c[]={"connect.exe"}; HANDLE handle;  HANDLE handle1; handle...

weixin_39706234的博客 2755

水声信号处理开源算法库最新进展

欢迎关注本专栏,一起探索新世界大家好,我是ZhuChunSHU。985院校硕士毕业,现担任算法研究员一职,热衷于深度学习算法研究与应用。曾获得阿里云天池比赛第三名,CCE比赛第五名,科大讯飞Q比赛第六名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法行业就业。希望和大家一起成长进步。今天继续我们的专栏分享!!!!!!!!!!!!!!!!!!!!水声信号处理是海洋科学与工程领域的核心组成部分,对于水下通信、目标探测、海洋环境监测以及生物声学研究至关重要。

u012133341的博客 1254

Linux C++ 通信 - 实现后台进程

每次终端关闭时,它的所有子进程也会因此而终止,显然,这是无法在实际运用中忽略的问题,此时,就需要把持续活动的进程移至后台运行。

m0_46684679的博客 1336

【单智能体】AI 数据分析智能体案例讲解(附完整源码)

本案例将引导您构建一个基于 AI 的数据分析智能体,让用户能够通过自然语言查询来分析 CSV 和 Excel 文件中的数据,无需掌握 SQL 知识。该智能体使用 Agno Agent 框架集成 OpenAI GPT-4o 模型,并利用 DuckDB 提供高效的数据处理能力。

rengang66的博客 238

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

C++后台进程编程实战

一点睛 对于那些不需要交互的进程,很多时候希望将其在后台启动,可以在启动的时候加一个&。比如一个进程的名字是recv,我们希望它在后台运行,则可以输入:recv &。这样它就是一个后台进程了,而且不会占据shell,我们依然可以在shell下做其他操作。但关闭shell窗口的时候,后台进程也将随之退出。我们把切换到后台运行的进程称为job。当一个进程以后台启动时候(即启动时加&...

实践求真知 1812

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

C++创建后台守护进程自动删除指定目录

C++文件流操作,自动删除指定目录

Fine的优快云博客 389

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

别再点‘忽略’了!一招揪出导致Visual C++弹窗的Adobe后台进程

本文详细解析了Visual C++ Runtime Library弹窗问题的根源,特别是由Adobe后台进程引发的Assertion failed错误。通过任务管理器和Process Monitor工具精准定位问题进程,并提供文件转移法和注册表清理等安全解决方案,帮助用户彻底消除这一顽固问题。

weixin_30889885的博客 617

MFC/VC/C++ 结束后台进程

结束进程, 直接传参调用,CloseProgram(_T("name.exe")); 代码实现如下: void CloseProgram(CString strProgram) { HANDLE handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);//获得系统快照句柄 PROCESSENTRY32 *...

weixin_38886498的博客 599

C++后台进程实现全解析,UE4报错:无法编译项目。

实现异步日志写入避免I/O阻塞。

lde6brfr的博客 28

C++ 后台进程 daemon

    bool Switcher::Daemon() { base::YamlConfig config; if (!config_.ReadConfig(config_file_)) { fprintf(stderr, "read config file fail.\n"); return false; } bool is_daemon = config_.G...

weixin_34409357的博客 408

C++并发编程之进程退出前,中断后台任务线程池的代码

在C++中,处理后台任务线程池并在进程退出前安全地中止和退出所有任务线程是一个常见的需求。

捕鲸叉的专栏 463

c++ fork 进程时 共享内存_C++ 后台开发面试时一般考察什么?

C++ 后台开发面试时一般考察什么?带领研发团队多年,现对应试者在面试中锁需要准备的知识进行总结,主要涉及C++/C/Golang语言基础,数据结构与算法,TCP/IP协议,网络编程,Linux。虽然面试技巧和心态也很重要,但这里只有24K纯技术干货,期望大家能够准备好,进入我司。点赞后,收藏吧!C和C++语言基础参考书籍:《C++ primer》,《effective C++》,《STL源码解析...

weixin_39579468的博客 176
上一篇: C++ 函数详解:从基础到高级应用
下一篇: Datagrip对个人免费开放
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值