C++ 多线程
                           
天天向上
发布: 2025-03-29 17:19:43

原创
701 人浏览过

C++ 多线程编程允许程序并行执行多个任务,这样可以有效地利用多核处理器,提高程序的性能和响应速度。C++11 引入了对多线程的标准支持,使得线程创建、同步和管理变得更加简单和直观。本文将详细介绍 C++ 中的多线程编程。

1. C++ 多线程基础

C++11 引入了 <thread> 头文件,它提供了创建和管理线程的标准接口。要使用多线程,需要包含 <thread> 头文件。

1.1 创建线程

C++ 使用 std::thread 类来表示和管理线程。线程的创建非常简单,创建线程时可以通过传递一个可调用对象(如函数、lambda 表达式、成员函数等)来启动线程。

#include <iostream>
#include <thread>

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

int main() {
    // 创建并启动线程
    std::thread t(print_hello);

    // 等待线程结束
    t.join();  // 阻塞主线程,直到 t 线程执行完毕

    return 0;
}

说明:

  • std::thread t(print_hello); 创建一个新线程并执行 print_hello 函数。
  • t.join() 阻塞主线程,直到 t 线程执行完毕。如果不调用 join()detach(),程序会终止时抛出异常。

1.2 join()detach()

  • join():阻塞当前线程,等待线程执行完毕后再继续执行。通常在主线程中调用 join() 来等待子线程的完成。
  • detach():使线程脱离当前线程,独立执行。脱离的线程在完成后不会影响主线程的结束,因此需要注意其生命周期。
#include <iostream>
#include <thread>

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

int main() {
    std::thread t(print_hello);
    t.detach();  // 脱离线程,不等待它完成

    std::cout << "Main thread continues execution." << std::endl;

    // 程序结束时,t 线程可能尚未执行完毕
    return 0;
}

说明:

  • t.detach() 会使 t 线程脱离主线程。脱离的线程在完成后不再需要主线程等待。

2. 线程参数传递

线程函数可以接受参数,这些参数可以通过值传递或引用传递。

2.1 值传递

#include <iostream>
#include <thread>

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

int main() {
    int number = 5;
    std::thread t(print_number, number);  // 值传递参数
    t.join();
    return 0;
}

说明:

  • 传递参数时,C++ 会自动将参数进行复制,即值传递。

2.2 引用传递

若要传递引用,可以使用 std::ref 来避免复制。

#include <iostream>
#include <thread>

void increment(int& n) {
    ++n;
    std::cout << "Incremented: " << n << std::endl;
}

int main() {
    int number = 5;
    std::thread t(increment, std::ref(number));  // 引用传递
    t.join();
    std::cout << "Main number: " << number << std::endl;
    return 0;
}

说明:

  • std::ref(number) 传递的是 number 的引用,而不是它的副本。这样 increment 函数可以直接修改原始数据。

3. 线程同步

在多线程环境中,多个线程可能会并发访问共享资源,造成数据竞态问题。C++ 提供了多种同步机制来解决这个问题,如互斥量(mutex)和条件变量(condition_variable)。

3.1 互斥量(mutex)

互斥量用于保证同一时刻只有一个线程访问共享资源。C++11 引入了 std::mutex,它提供了基本的互斥操作。

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

std::mutex mtx;  // 声明一个互斥量

void print_hello() {
    mtx.lock();  // 上锁
    std::cout << "Hello from thread!" << std::endl;
    mtx.unlock();  // 解锁
}

int main() {
    std::thread t1(print_hello);
    std::thread t2(print_hello);

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

    return 0;
}

说明:

  • std::mutex mtx; 声明一个互斥量对象。
  • mtx.lock() 上锁,保证当前线程独占对资源的访问。
  • mtx.unlock() 解锁,允许其他线程访问。

3.2 std::lock_guardstd::unique_lock

std::lock_guard 是一种简化的锁机制,它会在作用域结束时自动释放锁,从而避免了手动调用 unlock()

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

std::mutex mtx;

void print_hello() {
    std::lock_guard<std::mutex> lock(mtx);  // 自动上锁和解锁
    std::cout << "Hello from thread!" << std::endl;
}

int main() {
    std::thread t1(print_hello);
    std::thread t2(print_hello);

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

    return 0;
}

说明:

  • std::lock_guard 在构造时上锁,在析构时自动解锁,从而避免忘记解锁的错误。

3.3 条件变量(std::condition_variable

条件变量用于实现线程之间的通信。一个线程可以等待条件变量,另一个线程可以通过通知条件变量来唤醒等待的线程。

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

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

void print_hello() {
    std::unique_lock<std::mutex> lock(mtx);
    while (!ready) {
        cv.wait(lock);  // 等待条件变量
    }
    std::cout << "Hello from thread!" << std::endl;
}

int main() {
    std::thread t1(print_hello);
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lock(mtx);
        ready = true;  // 设置条件
    }
    cv.notify_one();  // 通知一个线程
    t1.join();
    return 0;
}

说明:

  • cv.wait(lock) 会让线程在条件变量上等待,直到另一个线程调用 cv.notify_one()cv.notify_all()
  • std::unique_lock 用于与条件变量一起工作,它可以在 waitnotify 过程中自动释放和获取锁。

4. 线程安全与并发问题

当多个线程并发访问共享资源时,必须确保对共享资源的访问是线程安全的。使用互斥量、条件变量、读写锁等同步机制可以避免数据竞争和死锁等问题。

  • 死锁:当多个线程互相等待对方释放资源时,程序会进入死锁状态。要避免死锁,可以通过设计合理的锁顺序、避免嵌套锁等方法来防止。
  • 数据竞争:多个线程同时修改共享变量而没有同步保护,可能导致不一致的结果。通过使用互斥量等同步机制可以避免数据竞争。

5. 小结

C++ 多线程编程提供了强大的工具来实现并发和并行处理。通过使用 std::thread 创建和管理线程,结合互斥量、条件变量等同步机制,可以编写高效且线程安全的程序。在进行多线程编程时,必须特别注意线程同步和共享资源访问的安全性。

发表回复 0

Your email address will not be published. Required fields are marked *