C++多线程编程超详解

欢迎来到我的网站,下面将为您介绍C++多线程编程的超详细攻略。

什么是多线程编程?

多线程是指程序中包含有两条或两条以上的路径(线程)可以同时运行。单线程就如同是一条车道的道路,而多线程就是在这条道路上增加了多个车道,可以同时通行。在程序设计中,单线程程序的执行是按照单一的线路顺序执行的,而多线程程序则可以根据多条线路的走向同时执行。

为什么要进行多线程编程?

在程序开发中,多线程编程可以带来很多好处。首先,多线程可以提高程序的响应速度,使得在程序执行任务时可以同时进行其他的操作,增加程序的效率。其次,多线程可以利用多核处理器,充分的利用CPU资源进行并行计算。

C++多线程编程基础

线程创建和启动

C++中可以通过std::thread类来实现线程的创建和启动。具体实现方法如下:

#include <iostream>
#include <thread>

void func() {
  std::cout << "Hello, Thread!" << std::endl;
}

int main() {
  std::thread t(func);

  t.join();

  return 0;
}

上述代码中,通过std::thread类的构造函数创建了一个新的线程,执行了名为func的函数。同时使用t.join()函数等待线程执行完毕并且回收资源。此时,在控制台中将输出Hello, Thread!

线程间的同步和互斥

在多线程编程中,线程间往往需要进行同步或互斥操作。C++中可以通过std::mutex类来实现互斥,通过std::condition_variable类来实现同步。

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

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void func() {
  std::unique_lock<std::mutex> lock(mtx);
  while (!ready) {
    cv.wait(lock);
  }
  std::cout << "Thread is ready!" << std::endl;
}

int main() {
  std::thread t(func);

  // do some work

  {
    std::lock_guard<std::mutex> lock(mtx);
    ready = true;
  }

  cv.notify_one();

  t.join();  

  return 0;
}

上述代码中,通过std::mutex类来实现了mtx互斥锁,通过std::condition_variable类来实现了cv条件变量,通过ready变量来控制线程任务的执行。创建了一个新的线程并执行func函数。同时在主线程中进行了一些工作,然后通过mtx锁修改了ready变量的值,并通过cv.notify_one()唤醒等待的线程。此时,在控制台中将输出Thread is ready!

示例说明

示例一 - 计算素数

下面的程序演示了如何使用多线程计算100000内的素数,并输出计算所用的时间。

#include <iostream>
#include <thread>
#include <vector>
#include <chrono>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void findPrime(unsigned int start, unsigned int end, std::vector<unsigned int>& primes) {
  for (auto i = start; i <= end; i++) {
    bool is_prime = true;

    for (auto j = 2; j < i; j++) {
      if (i % j == 0) {
        is_prime = false;
        break;
      }
    }

    if (is_prime) {
      std::lock_guard<std::mutex> lock(mtx);
      primes.push_back(i);
    }
  }
}

int main() {
  std::vector<unsigned int> primes;
  unsigned int threads_num = std::thread::hardware_concurrency();
  std::vector<std::thread> threads;

  std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

  for (auto i = 0; i < threads_num; i++) {
    threads.emplace_back([&primes, i, &threads_num]() {
      unsigned int start_num = i * 100000 / threads_num + 1;
      unsigned int end_num = (i + 1) * 100000 / threads_num;

      findPrime(start_num, end_num, primes);

      if (++ready == threads_num) {
        cv.notify_one();
      }
    });
  }

  std::unique_lock<std::mutex> lock(mtx);
  while (ready != threads_num) {
    cv.wait(lock);
  }

  std::chrono::system_clock::time_point end = std::chrono::system_clock::now();
  std::chrono::duration<double> diff = end - start;

  std::cout << "Time : " << diff.count() << std::endl;

  std::cout << "Result : ";
  for (auto&& p : primes) {
    std::cout << p << " ";
  }
  std::cout << std::endl;

  for (auto&& t : threads) {
    t.join();
  }

  return 0;
}

上述代码中,首先通过std::thread::hardware_concurrency()函数获取计算机的CPU核心数作为线程数。然后通过std::vector<std::thread>容器创建多个线程。每个线程计算一部分的素数,并将结果保存至共享的primes容器中。线程执行完毕后,通过计数ready的方式统计线程数,并通过cv.notify_one()来唤醒等待的线程。最后输出计算所用的时间和计算结果。

示例二 - 多线程下载

以下是一个用多线程方式下载文件的程序演示,可以同时下载多个文件并且每个文件都在独立的线程中下载。

#include <iostream>
#include <fstream>
#include <sstream>
#include <thread>
#include <vector>
#include <mutex>
#include <chrono>

std::mutex mtx;

void downloadFile(const std::string& url) {
  std::string filename = url.substr(url.find_last_of("/") + 1);
  std::stringstream ss;
  ss << std::this_thread::get_id();
  std::string id = ss.str();

  std::ofstream ofs(filename + "." + id, std::ios::out | std::ios::binary);
  if (!ofs) {
    std::cout << "Cannot open file for writing." << std::endl;
    return;
  }

  CURL* curl;
  CURLcode res;
  curl = curl_easy_init();
  if (curl) {
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
                     [](void* ptr, size_t size, size_t nmemb, void* userdata) -> size_t {
      static_cast<std::ofstream*>(userdata)->write(static_cast<char*>(ptr), size * nmemb);
      return size * nmemb;
    });
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ofs);

    res = curl_easy_perform(curl);

    if (res != CURLE_OK) {
      std::cout << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
    }

    curl_easy_cleanup(curl);
  }

  ofs.close();

  mtx.lock();
  std::cout << "Downloaded " << filename << "." << id << std::endl;
  mtx.unlock();
}

int main() {
  std::vector<std::thread> threads;
  std::vector<std::string> urls = {
    "http://ipv4.download.thinkbroadband.com/1MB.zip",
    "http://ipv4.download.thinkbroadband.com/5MB.zip",
    "http://ipv4.download.thinkbroadband.com/10MB.zip",
    "http://ipv4.download.thinkbroadband.com/20MB.zip",
    "http://ipv4.download.thinkbroadband.com/50MB.zip",
    "http://ipv4.download.thinkbroadband.com/100MB.zip",
    "http://ipv4.download.thinkbroadband.com/200MB.zip",
    "http://ipv4.download.thinkbroadband.com/512MB.zip",
    "http://ipv4.download.thinkbroadband.com/1GB.zip",
  };

  std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

  for (auto&& url : urls) {
    threads.emplace_back(std::thread(downloadFile, url));
  }

  for (auto&& t : threads) {
    t.join();
  }

  std::chrono::system_clock::time_point end = std::chrono::system_clock::now();
  std::chrono::duration<double> diff = end - start;

  std::cout << "Time : " << diff.count() << std::endl;

  return 0;
}

上述代码中,通过CURL库实现了文件的下载操作。然后通过std::vector<std::string>容器保存多个文件的URL,并通过std::vector<std::thread>容器创建多个线程,每个线程下载一个文件,并以线程ID作为下载文件名的后缀。最后输出下载所用的时间和下载结果。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++多线程编程超详解 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • 详解java解决分布式环境中高并发环境下数据插入重复问题

    详解 Java 解决分布式环境中高并发环境下数据插入重复问题 背景 在高并发环境下,数据插入操作很容易出现重复插入的问题。例如,多个用户同时提交一个相同的表单,系统可能会将同样的数据插入数据库中多次,造成数据不一致的问题。这种情况在分布式环境下尤其常见,因为不同节点的时间戳可能不一致。 解决方案 方法一:利用 Unique 约束 在数据库中设置 Unique…

    多线程 2023年5月16日
    00
  • Linux多线程编程(一)

    Linux多线程编程(一) 前言 Linux是一个多线程的操作系统,可以支持多个并发执行的程序。多线程编程可以充分利用多核CPU,在并发执行的情况下提高程序的性能,同时也可以编写出体验更加流畅、响应更快的应用程序。 本文将介绍Linux多线程编程,并提供两个示例说明,分别演示线程的创建和同步。 线程创建 在Linux中,线程的创建依赖于pthread库,因此…

    多线程 2023年5月17日
    00
  • golang基于errgroup实现并发调用的方法

    Golang基于errgroup实现并发调用的方法 在Golang中,errgroup是一个非常好用的并发控制库,它允许我们创建一组goroutine并发执行一系列的任务并监控它们的运行情况。本文将介绍如何使用errgroup实现并发调用的方法。 一、准备工作 在使用errgroup前,我们需要先引入它的包: import "golang.org/…

    多线程 2023年5月17日
    00
  • Java中多线程的ABA场景问题分析

    Java中多线程的ABA场景问题分析 ABA场景问题简介 多线程中,如果一个线程在读取一个共享变量时,另一个线程把它修改为另外一个值,再修改回原来的值,这时第一个线程可能会检查到期望的值,但是并没有发现这个值已经被修改过,这种情况就叫做ABA场景问题。 ABA场景问题如何解决 Java中提供了一个原子变量类AtomicStampedReference来解决A…

    多线程 2023年5月16日
    00
  • python多线程操作实例

    让我来为你详细讲解一下“Python多线程操作实例”的完整攻略。 Python多线程操作实例 多线程操作是提高Python程序运行速度和效率的关键技术之一。多线程是指一个进程中的多个线程同时执行独立任务的能力,这些线程可以并发执行或同时运行。 在Python中,我们可以使用threading模块来实现多线程编程。下面我将为你介绍Python多线程操作的实例和…

    多线程 2023年5月17日
    00
  • Java并发教程之Callable和Future接口详解

    Java并发教程之Callable和Future接口详解 在Java多线程编程中,Callable和Future是两个非常重要的接口。它们可以让我们方便地创建并发任务,并且可以在任务执行完毕后获取到任务的结果。本教程将详细讲解Callable和Future接口的使用方法和注意事项。 Callable接口 Callable接口是一个泛型接口,它定义了一个cal…

    多线程 2023年5月17日
    00
  • JavaScript多并发问题如何处理

    JavaScript多并发问题主要涉及到JavaScript的异步编程和事件循环机制。在JavaScript中,单线程的限制就意味着代码只能串行执行,而异步编程在处理I/O等IO密集型任务时,可能存在多个异步操作同时执行的情况,而这时就会出现多并发问题。 那么我们该如何解决这些多并发问题呢?以下是几个可以采用的策略: 1. 使用回调函数 在JavaScrip…

    多线程 2023年5月16日
    00
  • Spring事务处理Transactional,锁同步和并发线程

    我来为你详细讲解一下“Spring事务处理Transactional,锁同步和并发线程”的完整攻略。 Spring事务处理Transactional Spring的事务管理器提供了一种方便的方式来处理数据库的事务。对于需要保证数据库操作的原子性(ACID)的业务操作,我们常常使用Spring的@Transactional注解。 在一个Spring管理的bea…

    多线程 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部