Bootstrap

C++线程基础使用方法


C++ 中的线程是指程序中能够独立执行的一条控制流。线程允许在同一个进程中并发运行多个任务,从而提高程序的性能和响应性。C++11 标准引入了对线程的原生支持,通过 <thread> 标准库提供了一套工具来管理线程。


1. 什么是线程

线程是程序执行的基本单位,多个线程可以共享同一进程的资源(如内存、文件句柄等)。线程的使用场景包括:

  • 多任务并行处理(如同时处理用户输入和后台计算)。
  • 提高程序性能(利用多核 CPU)。
  • 异步操作(如非阻塞 I/O)。

2. C++ 中的线程库

C++ 标准库中的线程功能由头文件 <thread> 提供,主要包括:

  • std::thread:用于创建和管理线程。
  • std::mutex:用于线程同步,防止数据竞争。
  • std::condition_variable:用于线程间的条件通知。
  • std::futurestd::promise:用于线程间的结果传递。

3. 创建线程

基本用法
#include <iostream>
#include <thread>

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

int main() {
    std::thread t(task); // 创建并启动线程
    t.join();            // 等待线程完成
    return 0;
}

说明:

  • std::thread t(task):启动线程 t,执行函数 task
  • t.join():主线程等待子线程完成。如果没有调用 join()detach(),程序会报错。
使用 Lambda 表达式
#include <iostream>
#include <thread>

int main() {
    std::thread t([] {
        std::cout << "Hello from Lambda thread!" << std::endl;
    });
    t.join();
    return 0;
}
使用类成员函数
#include <iostream>
#include <thread>

class Task {
public:
    void operator()() const {
        std::cout << "Hello from class thread!" << std::endl;
    }
};

int main() {
    Task task;
    std::thread t(task); // 使用类的调用运算符
    t.join();
    return 0;
}

4. 管理线程

joindetach
  • join():等待线程执行完成。线程执行完成前,主线程会被阻塞。
  • detach():将线程与主线程分离,线程在后台继续运行。分离的线程无法再被主线程管理。
std::thread t(task);
t.detach();  // t 独立运行
检查线程是否可加入
if (t.joinable()) {
    t.join();
}

5. 数据共享与同步

数据竞争问题

多个线程共享数据时,可能会发生数据竞争(多个线程同时访问和修改同一资源)。

#include <iostream>
#include <thread>

int counter = 0;

void increment() {
    for (int i = 0; i < 100000; ++i) {
        ++counter;
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    std::cout << "Counter: " << counter << std::endl; // 结果可能不正确
    return 0;
}
使用互斥锁 (std::mutex)

互斥锁可以防止数据竞争。

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

int counter = 0;
std::mutex mtx;

void increment() {
    for (int i = 0; i < 100000; ++i) {
        std::lock_guard<std::mutex> lock(mtx); // 自动管理锁
        ++counter;
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    std::cout << "Counter: " << counter << std::endl; // 结果正确
    return 0;
}
死锁与避免

使用多个互斥锁时可能会发生死锁。可以使用 std::lock 同时锁定多个资源。

std::lock(mutex1, mutex2);

6. 条件变量

条件变量用于线程间的同步,使一个线程等待另一个线程的通知。

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

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

void worker() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, [] { return ready; }); // 等待通知
    std::cout << "Worker is running!" << std::endl;
}

int main() {
    std::thread t(worker);

    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lock(mtx);
        ready = true;
    }
    cv.notify_one(); // 通知线程
    t.join();
    return 0;
}

7. 线程间通信

使用 std::futurestd::promise
  • std::promise:允许线程间传递值。
  • std::future:用于获取异步结果。
#include <iostream>
#include <thread>
#include <future>

void compute(std::promise<int> p) {
    p.set_value(42); // 设置结果
}

int main() {
    std::promise<int> p;
    std::future<int> f = p.get_future();

    std::thread t(compute, std::move(p));
    std::cout << "Result: " << f.get() << std::endl; // 获取结果
    t.join();
    return 0;
}

8. 总结

C++ 的线程功能强大,可以用于实现高效的多任务并行处理。然而,开发多线程程序需要注意以下几点:

  1. 数据同步:通过 std::mutex 或其他机制避免数据竞争。
  2. 死锁问题:小心使用多个锁,合理设计锁的顺序。
  3. 资源管理:使用智能指针和 std::lock_guard 等工具确保资源安全。

正确地使用线程可以极大地提升程序的性能,但也增加了程序的复杂性和调试难度。

;