📜  C++多线程(1)

📅  最后修改于: 2023-12-03 15:29:55.199000             🧑  作者: Mango

C++多线程

在现代计算机系统中,多线程并发已经成为提高程序性能的重要途径之一。C++语言作为一门高级语言,在C++11标准中引入了并发编程的支持,使得C++语言具有了卓越的多线程编程能力。

C++11多线程基础知识

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() 函数等待其执行完成并返回结果。

C++11多线程的线程安全性

在多线程编程中,要注意线程安全性问题。下面是一个线程不安全的示例程序:

#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

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++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 执行策略,表示使用并行计算。

std::jthread

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++语言在并发编程方面的应用。开发人员可以使用这些能力来提高程序的性能,充分发挥计算机系统的并发能力。但需要注意的是,在多线程编程中一定要注意线程安全性,避免出现数据竞争等问题。