CPP多线程

2024-06-16 17:04
文章标签 多线程 cpp

本文主要是介绍CPP多线程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

什么是多线程?

        多线程是一种允许程序同时运行多个线程的技术。每个线程可以执行不同的任务,这在处理需要并发执行的操作时(例如,处理多个客户端的网络服务器,或者图形用户界面应用程序)非常有用。多线程能够提高程序的性能和响应速度。

C++ 标准库中的 std::thread

        在 C++11 标准中,引入了 std::thread 类,使得在 C++ 中进行多线程编程变得更为简单和直接。通过 std::thread,我们可以轻松地创建和管理多个线程。

        为了更清楚地展示多线程编程的优势,创建一个示例来比较使用多线程和不使用多线程的情况。我们将编写一个程序,模拟一个计算密集型任务,例如计算一系列大素数,并分别使用单线程和多线程执行这个任务,然后比较它们的运行时间。

任务说明

我们的任务是计算从某个大数开始的 N 个素数。我们将通过以下步骤来实现:

  1. 单线程实现: 使用一个循环逐个计算 N 个素数。
  2. 多线程实现: 将任务分成 T 个部分,每个部分由一个线程来处理。
  3. 比较运行时间: 测量并比较两种实现的运行时间。

代码实现

单线程版本

        首先,我们实现一个简单的单线程版本。

#include <iostream>
#include <cmath>
#include <chrono>// 检查一个数是否是素数
bool is_prime(int num) {if (num <= 1) return false;if (num <= 3) return true;if (num % 2 == 0 || num % 3 == 0) return false;for (int i = 5; i * i <= num; i += 6) {if (num % i == 0 || num % (i + 2) == 0) return false;}return true;
}// 计算从 start 开始的 n 个素数
void find_primes(int start, int n) {int count = 0;int num = start;while (count < n) {if (is_prime(num)) {std::cout << num << " ";count++;}num++;}std::cout << std::endl;
}int main() {int start = 100000;int n = 10; // 找到 10 个素数auto start_time = std::chrono::high_resolution_clock::now();find_primes(start, n);auto end_time = std::chrono::high_resolution_clock::now();std::chrono::duration<double> duration = end_time - start_time;std::cout << "Single-threaded duration: " << duration.count() << " seconds\n";return 0;
}

多线程版本

        接下来,我们实现一个多线程版本,将任务分成多个线程来处理。

#include <iostream>
#include <cmath>
#include <chrono>
#include <thread>
#include <vector>
#include <mutex>// 检查一个数是否是素数
bool is_prime(int num) {if (num <= 1) return false;if (num <= 3) return true;if (num % 2 == 0 || num % 3 == 0) return false;for (int i = 5; i * i <= num; i += 6) {if (num % i == 0 || num % (i + 2) == 0) return false;}return true;
}std::mutex mtx; // 互斥锁用于保护输出// 线程函数,计算从 start 开始的部分素数
void find_primes_thread(int start, int n, int thread_id) {int count = 0;int num = start;while (count < n) {if (is_prime(num)) {std::lock_guard<std::mutex> guard(mtx);std::cout << "Thread " << thread_id << ": " << num << "\n";count++;}num++;}
}int main() {int start = 100000;int n = 10; // 每个线程找到 10 个素数int num_threads = 4; // 使用 4 个线程std::vector<std::thread> threads;auto start_time = std::chrono::high_resolution_clock::now();// 启动多个线程,每个线程处理一部分工作for (int i = 0; i < num_threads; ++i) {threads.emplace_back(find_primes_thread, start + i * n, n, i);}// 等待所有线程完成for (auto& t : threads) {if (t.joinable()) {t.join();}}auto end_time = std::chrono::high_resolution_clock::now();std::chrono::duration<double> duration = end_time - start_time;std::cout << "Multi-threaded duration: " << duration.count() << " seconds\n";return 0;
}

代码解释

  1. 单线程版本:

    • find_primes 函数从 start 开始计算 n 个素数,并打印结果。
    • 使用 std::chrono 计时来测量执行时间。
  2. 多线程版本:

    • find_primes_thread 函数类似于单线程版本,但它有一个额外的 thread_id 参数,用于标识线程。
    • 使用 std::mutex 来保护控制台输出,防止多线程竞争导致输出混乱。
    • main 函数中,启动 num_threads 个线程,每个线程计算 n 个素数。每个线程的起始点不同,以避免重复计算。
    • 使用 std::vector<std::thread> 来存储线程对象,并在所有线程完成后调用 join

结果比较

        将这两个版本的程序分别编译和运行,会看到它们的执行时间。在大多数情况下,多线程版本的程序会比单线程版本快得多,尤其是在处理计算密集型任务时。

g++ -std=c++11 -o single_thread single_thread.cpp
./single_thread

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

 运行结果示例

       得到如下结果:

Single-threaded duration: 2.5 seconds
 

Thread 0: 100003
Thread 0: 100019
Thread 0: 100043
Thread 0: 100049
Thread 0: 100057
Thread 0: 100069
Thread 0: 100103
Thread 0: 100109
Thread 0: 100129
Thread 0: 100151
Thread 1: 100019
Thread 1: 100043
Thread 1: 100049
Thread 1: 100057
Thread 1: 100069
Thread 1: 100103
Thread 1: 100109
Thread 1: 100129
Thread 1: 100151
Thread 1: 100153
Thread 2: 100043
Thread 2: 100049
Thread 2: 100057
Thread 2: 100069
Thread 2: 100103
Thread 2: 100109
Thread 2: 100129
Thread 2: 100151
Thread 2: 100153
Thread 2: 100169
Thread 3: 100043
Thread 3: 100049
Thread 3: 100057
Thread 3: 100069
Thread 3: 100103
Thread 3: 100109
Thread 3: 100129
Thread 3: 100151
Thread 3: 100153
Thread 3: 100169
Multi-threaded duration: 0.00377134 seconds

结论

        通过这个示例,我们可以清楚地看到多线程编程的优势。多线程版本的程序可以显著地减少计算时间,特别是在任务可以被分割并行处理的情况下。这对于需要高性能和实时响应的应用程序来说非常重要。

        不过,需要注意的是,使用多线程也会带来一些复杂性,例如线程同步、数据竞争和死锁等问题。因此,在编写多线程程序时,必须谨慎处理这些潜在的风险。

 

这篇关于CPP多线程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1067026

相关文章

Android多线程下载见解

通过for循环开启N个线程,这是多线程,但每次循环都new一个线程肯定很耗内存的。那可以改用线程池来。 就以我个人对多线程下载的理解是开启一个线程后: 1.通过HttpUrlConnection对象获取要下载文件的总长度 2.通过RandomAccessFile流对象在本地创建一个跟远程文件长度一样大小的空文件。 3.通过文件总长度/线程个数=得到每个线程大概要下载的量(线程块大小)。

如何在Android中实现多线程与线程池?

目录 一、Android介绍二、什么是多线程三、什么是线程池四、如何在Android中实现多线程与线程池 一、Android介绍 Android是一种基于Linux内核的开源操作系统,由Google公司领导开发。它最初于2007年发布,旨在为移动设备提供一种统一、可扩展的操作系统。Android系统以其高度的可定制性和丰富的应用生态而受到广泛欢迎,如今已经成为全球最流行的

【c2】编译预处理,gdb,makefile,文件,多线程,动静态库

文章目录 1.编译预处理:C源程序 - 编译预处理【#开头指令和特殊符号进行处理,删除程序中注释和多余空白行】- 编译2.gdb调试:多进/线程中无法用3.makefile文件:make是一个解释makefile中指令的命令工具4.文件:fprint/fgets/fwrite/fread,ftell/rewind/fseek/fflush4.1 文本文件:FILE结构体4.2 二进制文件:没

多线程简单运用---时钟的实现

效果图:   代码: package game;import java.awt.BorderLayout;import java.awt.Color;import java.awt.Container;import java.awt.Font;import java.awt.event.ActionEvent;import java.awt.event.ActionListe

多线程的简单应用----彩票摇号器

效果图:   package game;import java.awt.BorderLayout;import java.awt.Container;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.util.Random;import javax.swing.JBu

通过简单的售票程序理解多线程

售票程序要求:1:多个窗口同时卖票  2:同一编号的票的不能多次卖出   错误程序解析: public class TicketDemo {public static void main(String[] args) {Ticket t1=new Ticket("窗口1:");Ticket t2=new Ticket("窗口2:");Ticket t3=new Ticket("窗口3

cpp随笔——浅谈右值引用,移动语义与完美转发

右值引用 什么是右值 在cpp11中添加了一个新的类型叫做右值引用,记作&&,而在开始今天的正文之前我们先来看一下什么是左值什么是右值: 左值(&):存储在内存中,有明确存储地址的数据右值(&&):临时对象,可以提供数据(不可取地址访问) 而在cpp11中我们可以将右值分为两种: 纯右值:非引用返回的临时变量,比如运算表达式产生的临时变量,原始字面量以及lambda表达式等将亡值:与右值

开源C++版AI画图大模型框架stable-diffusion.cpp开发使用初体验

stable-diffusion.cpp是一个C++编写的轻量级开源类AIGC大模型框架,可以支持在消费级普通设备上本地部署运行大模型进行AI画图,以及作为依赖库集成的到应用程序中提供类似于网页版stable-diffusion的功能。 以下基于stable-diffusion.cpp的源码利用C++ api来开发实例demo演示加载本地模型文件输入提示词生成画图,这里采用显卡CUDA加速计算,

多线程相关方法详解

Thread中的方法 start()   用start() 方法来启动线程,真正实现了多线程运行,这时无需等待run() 方法内代码执行完毕,而是直接继续执行下面的代码。通过start()方法启动一个线程后,线程处于就绪状态,并没有运行,一旦得到CPU时间片,就开始执行run()方法。 注意:多次start()启动一个线程是非法的 run()   run()称为线程体,它包含了要执

如何保证单例模式在多线程中的线程安全性

如何保证单例模式在多线程中的线程安全性         对大数据、分布式、高并发等知识的学习必须要有多线程的基础。这里讨论一下如何在多线程的情况下设计单例模式。在23中设计模式中单例模式是比较常见的,在非多线程的情况下写单例模式,考虑的东西会很少,