C++线程及thread库常用函数方法的详解

C++ 的 std::thread 库是 C++11 引入的一个标准库,用于创建和管理线程。线程允许程序并发地执行代码,即使在同一个处理器上也可以通过时间切片的方式进行并发。多线程编程能提升应用程序的响应性和性能,特别是在多核处理器上。

1. std::thread 基本用法

创建线程

C++ 中可以使用 std::thread 类创建并启动线程,每个线程在后台独立执行传入的任务。线程的任务可以是函数、成员函数或 Lambda 表达式。

#include <iostream>
#include <thread>

void print_message() {
    std::cout << "Hello from thread!" << std::endl;
}

int main() {
    std::thread t(print_message);  // 创建一个新线程执行 print_message 函数
    t.join();  // 等待线程 t 完成
    return 0;
}

其中,线程 t 执行 print_message 函数。当 t.join() 被调用时,主线程会等待子线程 t 执行完成后再继续执行。

2. Lambda 表达式作为线程任务

可以使用 Lambda 表达式来作为线程的任务,使代码更加简洁。

#include <iostream>
#include <thread>

int main() {
    std::thread t([]{
        std::cout << "Hello from Lambda thread!" << std::endl;
    });

    t.join();  // 等待线程完成
    return 0;
}

3. 线程与参数传递

可以将参数传递给线程函数,包括按值传递和按引用传递。

按值传递

默认情况下,线程会将传入的参数按值传递给线程函数。

#include <iostream>
#include <thread>

void print_number(int n) {
    std::cout << "Number: " << n << std::endl;
}

int main() {
    int x = 10;
    std::thread t(print_number, x);  // 按值传递
    t.join();
    return 0;
}
按引用传递

如果希望按引用传递参数,需要使用 std::ref 将变量包裹。

#include <iostream>
#include <thread>

void increment(int& n) {
    ++n;
}

int main() {
    int x = 10;
    std::thread t(increment, std::ref(x));  // 按引用传递 x
    t.join();
    std::cout << "x after thread: " << x << std::endl;  // 输出 11
    return 0;
}

4. 库函数 join() 和 detach()

join()

join() 会阻塞主线程,直到子线程完成。这确保主线程等待所有工作线程结束后再继续执行。若没有调用 join(),主线程可能会在子线程完成之前结束。

std::thread t(task);
t.join();  // 等待 t 完成
detach()

detach() 会将线程与当前线程分离,使其在后台独立运行,主线程无需等待它完成。调用 detach() 后,线程在后台执行完成后自动释放资源。此方法适合那些无需等待其结束的任务。

std::thread t(task);
t.detach();  // t 在线程后台独立执行

注意: detach() 后主线程不会再追踪该线程,不能再 join() 已分离的线程,线程结束后资源自动释放,可能会导致资源泄漏或访问非法内存等问题,因此要谨慎使用。

5. std::thread 的常用方法

以下是 std::thread 类中的一些常用方法:

join()

阻塞当前线程,直到调用 join() 的线程完成。

detach()

使线程在后台独立运行,不与主线程同步。

joinable()

判断线程是否可以被 join()。如果线程已经 join()detach(),则 joinable() 返回 false

std::thread t(task);
if (t.joinable()) {
    t.join();
}
get_id()

返回线程的 ID,作为 std::thread::id 类型。如果线程还没有启动或者已经完成,ID 可能是一个特殊值。

std::thread t(task);
std::cout << "Thread ID: " << t.get_id() << std::endl;
hardware_concurrency()

返回系统中可能的并发线程数,即 CPU 核心数。这是一个静态方法,可以用于确定程序中应使用多少个线程。

unsigned int cores = std::thread::hardware_concurrency();
std::cout << "Number of cores: " << cores << std::endl;

6. 线程同步

多线程编程中,线程之间共享资源可能会引发数据竞争。为了防止这种情况,需要使用同步机制。C++ 提供了多种线程同步工具,包括互斥锁(std::mutex)、条件变量(std::condition_variable)、锁定器(std::lock_guard)等。

互斥锁 std::mutex

std::mutex 是一种互斥锁,可以防止多个线程同时访问共享数据。

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

std::mutex mtx;

void print_message(const std::string& message) {
    std::lock_guard<std::mutex> lock(mtx);  // 自动加锁与解锁
    std::cout << message << std::endl;
}

int main() {
    std::thread t1(print_message, "Thread 1: Hello");
    std::thread t2(print_message, "Thread 2: World");

    t1.join();
    t2.join();

    return 0;
}
  • std::lock_guard<std::mutex> 是一个封装类,它会自动管理互斥锁的锁定和解锁,避免手动调用 lock()unlock()
条件变量 std::condition_variable

条件变量允许线程等待某个条件发生,并在条件满足时通知其他线程。这在生产者-消费者模型中非常有用。

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

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

void wait_for_signal() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, [] { return ready; });
    std::cout << "Thread received signal!" << std::endl;
}

void send_signal() {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lock(mtx);
        ready = true;
    }
    cv.notify_one();  // 通知等待的线程
}

int main() {
    std::thread t1(wait_for_signal);
    std::thread t2(send_signal);

    t1.join();
    t2.join();

    return 0;
}
  • cv.wait() 会阻塞线程,直到接收到信号(即 notify_one()notify_all() 被调用),并且条件满足。

7. std::future 和 std::async

std::futurestd::async 提供了一种更高层次的线程处理方式,它允许启动异步任务并获取任务的结果,而无需手动管理线程。

#include <iostream>
#include <future>

int compute_sum(int a, int b) {
    return a + b;
}

int main() {
    std::future<int> result = std::async(compute_sum, 10, 20);  // 异步任务
    std::cout << "Result: " << result.get() << std::endl;  // 获取结果
    return 0;
}
  • std::async 启动一个异步任务,并返回 std::future 对象,通过调用 get() 来获取异步任务的结果。

8. 线程池(Thread Pool)

在实际应用中,线程池是一种常见的优化策略,它避免了反复创建和销毁线程的开销。C++ 标准库没有内建的线程池实现,但可以自己实现一个简单的线程池,或使用第三方库(如 Boost)。

一个简化版的线程池例子:

#include <iostream>
#include <vector>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <functional>

class ThreadPool {
public:
    ThreadPool(size_t numThreads);
    ~ThreadPool();
    void enqueue(std::function<void()> task);

private:
    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;
    std::mutex queueMutex;
    std::condition_variable condition;
    bool stop;

    void worker();
};

ThreadPool::ThreadPool(size_t numThreads) : stop(false) {
    for (size_t i = 0; i < numThreads; ++i) {
        workers.emplace_back(&ThreadPool::worker, this);
    }
}

ThreadPool::~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值