欢迎来到我的网站,下面将为您介绍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技术站