C++创建多线程的方法总结

news2024/9/23 15:21:34

        下个迭代有个任务很有趣,用大量的线程去访问一个接口,直至其崩溃为止,这就需要多线程的知识,这也不是什么难事,总结一下C++中的多线程方法:std、boost、pthread、windows api。

目录

一、多线程预备知识

二、C++11 std::thread 

2.1 创建线程

2.2 线程管理

2.3 传递参数

2.4 线程间通信 

2.4.1 使用共享变量和互斥量(互斥锁):

2.4.2 使用共享内存

2.5 其他线程相关信息

三、boost多线程库

四、POSIX线程(Linux&Unix) 

五、 Windows线程库

5.1 进程使用

5.2 进程通信


一、多线程预备知识

        多线程本质是将程序的运行拆分为部分,每个线程都有自己的执行上下文,包括它的程序计数器,寄存器和栈,并且它们独立地执行,互不干扰。我们必须要明确的是多线程的实现依赖硬件条件:多线程需要多核处理器。多核处理器可以同时执行多个线程,因此多线程可以利用多核处理器的多个内核来实现更快的处理速度和更高的性能。通过使用多核处理器,可以把多个线程并行执行,从而实现更高的性能和更快的处理速度。

        比如说,在图像处理应用中,如果使用多核处理器,可以把图像处理任务分成多个独立的部分,并使用多个线程分别执行每个部分。每例如,线程 1 可以处理图像的颜色校正,线程 2 可以处理图像的缩放,线程 3 可以处理图像的旋转等。由于每个线程都可以同时执行,因此处理速度比单线程处理要快得多。需要注意的是,在这种情况下,还需要考虑线程间的同步和通信,以确保线程之间的数据一致性。

二、C++11 std::thread 

2.1 创建线程

#include <iostream>
#include <thread>

void foo()
{
    std::cout << "Hello from thread" << std::endl;
}

int main()
{
    std::thread t1(foo);
    t1.join();

    return 0;
}

        在上面的代码中,通过 std::thread t1(foo) 创建了一个新线程,并在新线程中执行了函数 foo。 

2.2 线程管理

#include <iostream>
#include <thread>

void foo()
{
    std::cout << "Hello from thread" << std::endl;
}

int main()
{
    std::thread t1(foo);
    t1.join();
    t1.detach();

    return 0;
}

        在上面的代码中,通过调用 t1.join() 可以等待线程 t1 结束,并通过调用 t1.detach() 可以分离线程 t1,使线程在后台运行。 

   std::thread::detach() 方法是分离线程的方法,通过调用 detach() 方法,可以让线程在后台独立运行,不需要等待线程结束即可返回。与调用 join() 方法不同,分离的线程不受父线程的控制,因此如果父线程结束,分离的线程不会因此结束。请注意,分离的线程一旦开始执行,它将独立运行,不受任何控制,因此不能在父线程中等待它的结束或者通过其他方式获取其结果。如果需要等待线程结束,请使用 join() 方法。

        分离线程的主要作用是让线程在后台独立运行,不需要等待线程结束即可返回。这样可以在不需要等待线程结束的情况下,在父线程中执行其他任务,从而提高程序的效率。

2.3 传递参数

#include <iostream>
#include <thread>

void foo(int x)
{
    std::cout << "Hello from thread, x = " << x << std::endl;
}

int main()
{
    std::thread t1(foo, 10);
    t1.join();

    return 0;
}

        在上面的代码中,通过在创建线程时传递参数 10,并在函数 foo 中读取参数,实现了在线程中传递参数的功能。

2.4 线程间通信 

2.4.1 使用共享变量和互斥量(互斥锁):

#include <iostream>
#include <thread>
#include <mutex>

int g_num = 0;
std::mutex g_num_mutex;

void print_num() {
    while (true) {
        g_num_mutex.lock();
        if (g_num >= 100) {
            g_num_mutex.unlock();
            break;
        }
        std::cout << "Thread " << std::this_thread::get_id() << ": " << g_num++ << std::endl;
        g_num_mutex.unlock();
    }
}

int main() {
    std::thread t1(print_num);
    std::thread t2(print_num);

    t1.join();
    t2.join();

    return 0;
}

        我们定义了一个全局变量g_num,两个线程分别运行print_num函数。print_num函数不断地对g_num变量进行读写操作,并使用互斥量g_num_mutex对该变量进行加锁。这样可以确保在每次读写操作时,不会有其他线程访问g_num变量。如果g_num的值已经大于等于100,则表示线程退出。最后主线程调用join函数,等待其他线程退出。

 2.4.2 使用共享内存

#include <iostream>
#include <thread>
#include <string>

using namespace std;

string message;

void write_message()
{
    message = "Hello World";
}

void read_message()
{
    cout << message << endl;
}

int main()
{
    thread t1(write_message);
    thread t2(read_message);

    t1.join();
    t2.join();

    return 0;
}

2.5 其他线程相关信息

  • std::thread::hardware_concurrency():返回当前系统支持的最大线程数。

  • std::thread::native_handle():返回线程的原生句柄,在不同的平台中可能不同。

  • std::thread::joinable():判断线程是否可以被 join,如果线程已经结束或者被分离,则返回 false。

  • std::thread::join():等待线程结束,直到线程结束才返回。

  • std::thread::detach():分离线程,使线程可以在后台运行,并且不需要等待其结束。

  • std::thread::get_id() :返回线程ID。

三、boost多线程库

官方文档:

Chapter 38. Thread 4.8.0 - 1.73.0

        Boost 库中的 boost::thread 类可以方便地创建和管理多线程。以下是一个使用 Boost 库中的 boost::thread 类创建多线程的简单示例:

#include <iostream>
#include <boost/thread.hpp>

void worker_thread()
{
    std::cout << "Worker thread is running" << std::endl;
}

int main()
{
    boost::thread worker(worker_thread);
    std::cout << "Main thread is running" << std::endl;
    worker.join();

    return 0;
}

四、POSIX线程(Linux&Unix) 

        C++ POSIX 线程(pthread)库可以帮助您在 C++ 中创建和管理多线程。下面是一个创建和启动一个新线程的示例代码:

#include <pthread.h>
#include <iostream>

void *thread_func(void *arg)
{
    std::cout << "Thread started with argument: " << *((int *)arg) << std::endl;
    return NULL;
}

int main()
{
    pthread_t thread_id;
    int arg = 42;

    // 创建新线程
    int result = pthread_create(&thread_id, NULL, thread_func, &arg);
    if (result != 0) {
        std::cerr << "Error: pthread_create() failed" << std::endl;
        return 1;
    }

    // 等待线程结束
    result = pthread_join(thread_id, NULL);
    if (result != 0) {
        std::cerr << "Error: pthread_join() failed" << std::endl;
        return 1;
    }

    return 0;
}

        这段代码中,pthread_create 函数用于创建一个新线程,并启动它。第一个参数是一个指向线程 ID 的指针,第二个参数指定了线程的属性,通常为 NULL,第三个参数是线程函数的地址,最后一个参数是传递给线程函数的参数。

   pthread_join 函数等待线程结束,第一个参数是线程 ID,第二个参数是接收线程返回值的指针,通常为 NULL

五、 Windows线程库

5.1 进程使用

        下面是使用Windows API创建线程并打印数字并获取重要的线程信息的代码示例:

#include <iostream>
#include <Windows.h>

DWORD WINAPI ThreadFunction(LPVOID lpParam)
{
    // 获取当前线程ID
    DWORD threadId = GetCurrentThreadId();
    std::cout << "Thread ID: " << threadId << std::endl;

    // 获取线程传入的参数
    int threadParam = *(int*)lpParam;
    for (int i = 0; i < threadParam; i++)
    {
        std::cout << i << std::endl;
    }
    return 0;
}

int main()
{
    int num = 10;

    // 创建线程
    HANDLE hThread = CreateThread(NULL, 0, ThreadFunction, &num, 0, NULL);

    // 等待线程结束
    WaitForSingleObject(hThread, INFINITE);

    // 关闭线程句柄
    CloseHandle(hThread);

    return 0;
}

5.2 进程通信

        在 Windows API 中,可以使用 CreateThread 函数创建线程,以下是通过共享变量实现线程间通信的代码示例:

#include <Windows.h>
#include <iostream>

DWORD WINAPI ThreadFunction1(LPVOID lpParam)
{
    int* sharedVariable = (int*)lpParam;
    while (true)
    {
        if (*sharedVariable == 0)
        {
            std::cout << "Thread 1: sharedVariable = " << *sharedVariable << std::endl;
            *sharedVariable = 1;
        }
    }
    return 0;
}

DWORD WINAPI ThreadFunction2(LPVOID lpParam)
{
    int* sharedVariable = (int*)lpParam;
    while (true)
    {
        if (*sharedVariable == 1)
        {
            std::cout << "Thread 2: sharedVariable = " << *sharedVariable << std::endl;
            *sharedVariable = 0;
        }
    }
    return 0;
}

int main()
{
    int sharedVariable = 0;
    HANDLE hThread1 = CreateThread(NULL, 0, ThreadFunction1, &sharedVariable, 0, NULL);
    HANDLE hThread2 = CreateThread(NULL, 0, ThreadFunction2, &sharedVariable, 0, NULL);
    WaitForMultipleObjects(2, &hThread1, TRUE, INFINITE);
    CloseHandle(hThread1);
    CloseHandle(hThread2);
    return 0;
}

    在主函数中,我们调用了 CreateThread 函数创建了两个线程,将共享变量 sharedVariable 的地址作为参数传入。线程 1 和线程 2 都通过判断共享变量的值来实现通信,它们每当共享变量的值变化时都会输出当前的值。  

在这个例子中,WaitForMultipleObjects函数将等待两个线程hThread1和hThread2完成,并且要求等待所有事件对象完成,因此参数bWaitAll的值为TRUE。并且dwMilliseconds的值为INFINITE,所以等待时间是无限的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/341142.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

图解浏览器渲染页面详细过程

渲染详细过程 产生渲染任务&#xff0c;开启渲染流程 当浏览器的网络线程收到 HTML 文档后&#xff0c;会产生一个渲染任务&#xff0c;并将其传递给渲染主线程的消息队列。 在事件循环机制的作用下&#xff0c;渲染主线程取出消息队列中的渲染任务&#xff0c;开启渲染流程。…

IDEA 常用快捷键回顾

一 Alt 数字键 1. Alt 1: 打开项目 2. Alt 2: 打开Favorites 3. Alt 3: 打开Find 4. Alt 4: 打开Run 5. Alt 5: 打开Debug 6. Alt 6: 打开当前所在文件 7. Alt 7: 打开Structure 8. Alt 8: 打开Services 9. Alt 9: 打开Git日志 二 Ctrl 其他键 1. Ctrl…

【Flink】详解JobGraph

概述 JobGraph 是 StreamGraph 优化后的产物&#xff0c;客户端会将优化后的 JobGraph 发送给 JM。接下来的文章涉及到一些前置知识点&#xff0c;没有看前几期的小伙伴最好看一下前几期&#xff1a; 【Flink】详解StreamGraph【Flink】浅谈Flink架构和调度【Flink】详解Flin…

【Flutter入门到进阶】Dart进阶篇---进阶用法

1 Dart对象扩展 1.1 extension 1.1.1 介绍 可以在不更改类或创建子类的情况下&#xff0c;向类添加扩展功能的一种方式。灵活使用 extension 对基础类进行扩展&#xff0c;对开发效率有显著提升。 1.1.2 需求 在开发项目中碰到需求&#xff1a;将单位为分的数值转换成单位为…

RabbitMQ(黑马spring cloud笔记)

MQ 目录MQ一、同步通讯和异步通讯1. 同步通讯2. 异步通讯二、RabbitMQ1. 部署2. 架构3. 常见消息模型3.1 基本消息队列&#xff08;Basic Queue&#xff09;3.2 工作消息队列&#xff08;Work Queue&#xff09;3.3 发布订阅&#xff08;Publish、Subscribe&#xff09;4. 消息…

TPAMI 2022 | RC-Explainer:图神经网络的强化因果解释器

文章目录 一、论文关键信息二、基础概念三、主要内容1. Motivations2. Insights3. 解决方案的关键四、总结与讨论CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 一、论文关键信息 论文标题:Reinforced Causal Explainer for Graph Neural Networks 期刊信息:IEEE Transact…

【C++】内存管理

&#x1f345;不同的数据放在不同的地方&#xff0c;需要内存管理 目录 ☃️1.C/C中的内存分布 ☃️2.C语言中动态内存管理方式 ☃️3.C内存管理方式 &#x1f41d;3.1 new/delete操作内置类型 &#x1f41d;3.2 new和delete操作自定义类型 &#x1f41d;3.3 operator n…

FISCO BCOS节点扩容和使用console进行群组扩容

一、安装并启动FISCO BCOS 搭建单机单群组4节点的教程查看&#xff1a;https://blog.csdn.net/yueyue763184/article/details/128924144?spm1001.2014.3001.5501 二、下载扩容脚本 在fisco目录下输入以下命令&#xff1a; curl -#LO https://raw.githubusercontent.com/FI…

155、【动态规划】leetcode ——474. 一和零:三维数组+二维滚动数组(C++版本)

题目描述 原题链接&#xff1a;474. 一和零 解题思路 &#xff08;1&#xff09;三维数组 本题是要在已有的字符串中&#xff0c;找到给定的m个0和n个1&#xff0c;组出最大的子集。将字符串集合中的各个字符串看作物品&#xff0c;m个0和n个1看作背包的重量&#xff0c;则该…

jenkins +docker+python接口自动化之jenkins容器安装python3(二)

jenkins dockerpython接口自动化之jenkins容器安装python3&#xff08;二&#xff09; 目录&#xff1a;导读 前提是在docker下已经配置好jenkins容器了&#xff0c;是将python安装在jenkins容器下的 1、先看你的jenkins是否安装好 2、以root权限进入jenkins容器&#xff1…

NLP方向的论文可投的核心期刊

目录1、《计算机仿真》北大核心、科技核心2、《通信学报》北大核心、科技核心、CSCD核心3、《计算机科学》北大核心、EI来源期刊、CSCD核心4、《计算机工程》北大核心、科技核心5、《计算机应用》北大核心、科技核心、CSCD核心6、《计算机工程与应用》北大核心、科技核心、CSCD…

Python - 数据容器dict(字典)

目录 字典的定义 字典数据的获取 字典的嵌套 字典的各种操作 新增与更新元素 [Key] Value 删除元素 pop和del 清空字典 clear 获取全部的键 keys 遍历字典 容器通用功能总览 字典的定义 使用{}&#xff0c;不过存储的元素是一个个的&#xff1a;键值对&#…

golang的web框架Gin(一)---Gin的Resutful风格

Restful风格是什么&#xff1f; REST与技术无关&#xff0c;代表的是一种软件架构风格&#xff0c;REST是Representational State Transfer的简称&#xff0c;中文翻译为“表征状态转移”或“表现层状态转化”。 RESTFUL特点包括&#xff1a; 每一个URI代表1种资源&#xff…

STM32F103C8T6—库函数应用I2C/SPI驱动OLED显示中文、字符串

文章目录1. I2C与SPI通信协议对比2. 四脚OLED与六脚OLED3. I2C驱动OLED显示oled.h & oled.c&#xff1a;汉字取模 & oledfont.h&#xff1a;main.c 显示示例&#xff1a;连线方法&#xff1a;4. SPI驱动OLED显示1. I2C与SPI通信协议对比 I2C&#xff08;Inter-Integra…

基于springboot的毕业设计管理系统

摘要随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&…

【开源】祁启云网络验证系统V1.11

简介 祁启云免费验证系统 一个使用golang语言、Web框架beego、前端Naive-Ui-Admin开发的免费网络验证系统 版本 当前版本1.11 更新方法 请直接将本目录中的verification.exe/verification直接覆盖到你服务器部署的目录&#xff0c;更新前&#xff0c;请先关闭正在运行的验…

搭建云端vscode-server,使用web ide进行远程开发

使用乌班图系统&#xff0c;搭建自己的网页vs code开发环境github地址&#xff1a;GitHub - coder/code-server: VS Code in the browser安装脚本curl -fsSL https://code-server.dev/install.sh | sh出现deb package has been installed.表示已经正确安装。测试启动2.1修改配置…

Idea打包springboot项目war包,测试通过

pom.xml文件 <!--包名以及版本号&#xff0c;这个是打包时候使用&#xff0c;版本可写可不写&#xff0c;建议写有利于维护系统--> <artifactId>tsgdemo</artifactId> <version>0.0.1-SNAPSHOT</version> <!--打包形式--> <packaging&…

在项目中遇到的关于form表单的问题

前言 以下内容都是基于element Plus 和 vue3 一个form-item校验两个下拉框 有时候不可避免会遇到需要一个form-item校验两个下拉框的情况&#xff0c;比如&#xff1a; 这种情况下传统的校验已经无法实现&#xff0c;需要通过form表单提供的自定义校验来实现。以上面的必填…

6年软件测试经验,从我自己的角度理解自动化测试

接触了不少同行&#xff0c;由于他们之前一直做手工测试&#xff0c;现在很迫切希望做自动化测试&#xff0c;其中不乏工作5年以上的人。 本人从事软件自动化测试已经近6年&#xff0c;从server端到web端&#xff0c;从API到mobile&#xff0c;切身体会到自动化带来的好处与痛楚…