📅  最后修改于: 2023-12-03 15:29:55.199000             🧑  作者: Mango
在现代计算机系统中,多线程并发已经成为提高程序性能的重要途径之一。C++语言作为一门高级语言,在C++11标准中引入了并发编程的支持,使得C++语言具有了卓越的多线程编程能力。
C++11标准引入了 <thread>
头文件,该头文件包含了创建、销毁、管理线程的类和函数。下面是一个简单的多线程示例程序:
#include <iostream>
#include <thread>
#include <chrono>
void worker_thread()
{
// 模拟工作线程
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "Work done in worker thread" << std::endl;
}
int main()
{
// 创建新线程并开始执行
std::thread thread_worker(worker_thread);
// 主线程继续执行
std::cout << "Main thread continues to work" << std::endl;
// 等待工作线程执行完成
thread_worker.join();
return 0;
}
在上述代码中,我们使用 std::thread
类创建了一个工作线程,并在该线程中执行了 worker_thread()
函数。主线程继续执行,并在工作线程执行完成后使用 join()
函数等待其执行完成并返回结果。
在多线程编程中,要注意线程安全性问题。下面是一个线程不安全的示例程序:
#include <iostream>
#include <thread>
#include <string>
class MyClass
{
public:
void print(const std::string& str)
{
// 线程不安全的代码
std::cout << "Thread ID = " << std::this_thread::get_id() << ": " << str << std::endl;
}
};
void worker_thread(MyClass& obj)
{
obj.print("Worker thread is working");
}
int main()
{
MyClass obj;
std::thread thread_worker(worker_thread, std::ref(obj));
obj.print("Main thread is working");
thread_worker.join();
return 0;
}
在上述代码中,我们定义了一个 MyClass
类,并在类中定义了一个 print()
函数。该函数使用 std::cout
输出字符串,并输出线程 ID 以区分不同的线程。我们同时创建了一个工作线程并在其中调用 worker_thread()
函数,该函数使用 print()
函数输出一段字符串。在主线程中,我们也调用了 print()
函数输出一段字符串。如果运行这段代码,我们可能会得到类似于以下的输出:
Thread ID = 140056221261824: Worker thread is working
Main thread is working
Thread ID = 140056221261824: Main thread is working
可以看到,由于使用了全局的 std::cout
,导致输出混杂在一起,无法区分不同线程的输出。如果我们想要正确输出不同线程分别输出的内容,需要采取措施,例如使用互斥锁进行同步,避免多个线程同时写入一个共享数据。修改后的线程安全代码如下:
#include <iostream>
#include <thread>
#include <string>
#include <mutex>
class MyClass
{
public:
void print(const std::string& str)
{
std::lock_guard<std::mutex> lock(m_mutex);
std::cout << "Thread ID = " << std::this_thread::get_id() << ": " << str << std::endl;
}
private:
std::mutex m_mutex;
};
void worker_thread(MyClass& obj)
{
obj.print("Worker thread is working");
}
int main()
{
MyClass obj;
std::thread thread_worker(worker_thread, std::ref(obj));
obj.print("Main thread is working");
thread_worker.join();
return 0;
}
在修改后的代码中,我们在 MyClass
类中添加了一个互斥锁,并在 print()
函数中使用 std::lock_guard<std::mutex>
对互斥锁进行了包装,保证了线程安全性。
C++11标准中还引入了异步Executors,提供了异步执行任务的机制,可以方便地创建并行计算模型。下面是异步执行任务的示例程序:
#include <iostream>
#include <future>
int worker_task()
{
// 模拟耗时计算
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
return 42;
}
int main()
{
// 创建异步执行任务
std::future<int> future_result = std::async(std::launch::async, worker_task);
// 主线程继续执行
std::cout << "Main thread continues to work" << std::endl;
// 获取异步执行结果
int result = future_result.get();
std::cout << "Result = " << result << std::endl;
return 0;
}
在上述代码中,我们使用 std::async()
函数创建了一个异步任务,并在该任务中执行了 worker_task()
函数。在主线程中,我们使用 future
类等待异步任务执行的结果,并获取了执行结果。
在C++17标准中,C++语言又加入了一些新的多线程特性,进一步加强了C++语言在多线程编程中的地位。
C++17标准中引入了一系列的并行算法,如 std::for_each()
、std::transform()
和 std::reduce()
等,用于方便地对数据进行并行处理。下面是一个并行计算范围内整数和的示例程序:
#include <iostream>
#include <numeric>
#include <vector>
#include <execution>
int main()
{
std::vector<int> data(1000000, 1);
int result = std::reduce(std::execution::par, data.begin(), data.end());
std::cout << "Result = " << result << std::endl;
return 0;
}
在上述代码中,我们创建了一个包含1000000个元素的整型向量,并使用 std::reduce()
算法计算向量中所有元素的和,其中我们使用了默认的 std::execution::par
执行策略,表示使用并行计算。
C++17标准中引入了 std::jthread
类,该类封装了 std::thread
类,并在其基础上添加了管理线程取消的能力。下面是一个使用 std::jthread
类取消线程的示例程序:
#include <iostream>
#include <chrono>
#include <thread>
#include <stop_token>
void worker_thread(std::stop_token stop_token)
{
// 模拟工作线程,当 stop_token 请求取消时退出线程
while (!stop_token.stop_requested())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "Work done in worker thread" << std::endl;
}
}
int main()
{
std::jthread thread_worker(worker_thread);
std::cout << "Main thread continues to work" << std::endl;
// 请求取消线程
thread_worker.request_stop();
return 0;
}
在上述代码中,与使用 std::thread
的示例一样,我们创建了一个工作线程并在其中执行 worker_thread()
函数。区别在于,我们使用 std::stop_token
对线程进行了管理,并使用 request_stop()
函数请求取消线程的执行。
C++11以及C++17标准中引入的多线程编程能力极大地扩展了C++语言在并发编程方面的应用。开发人员可以使用这些能力来提高程序的性能,充分发挥计算机系统的并发能力。但需要注意的是,在多线程编程中一定要注意线程安全性,避免出现数据竞争等问题。