马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
C++多线程编程
概述
多线程编程允许在同一个步调中同时实验多个任务,从而进步步调的服从,特别是在处理处罚 I/O 麋集型或盘算麋集型任务时。C++11 引入了标准库中的多线程支持,使得 C++ 开辟者可以或许更加方便地举行多线程编程。
线程根本
线程是步调中实验的最小单位,每个线程有本身的步调计数器、堆栈和局部变量。C++ 的 库提供了对线程的支持,允许我们在步调中启动多个并行的线程。
线程的创建与管理
要创建一个线程,起首须要包罗 头文件。通过 std::thread 类可以创建线程。
创建线程
- #include <iostream>
- #include <thread>
- void print_hello() {
- std::cout << "Hello from thread!" << std::endl;
- }
- int main() {
- std::thread t(print_hello); // 创建一个线程,调用 print_hello 函数
- t.join(); // 等待线程执行完成
- return 0;
- }
复制代码 表明:
- std::thread 构造函数吸取一个函数作为参数,该函数将在新线程中实验。
- t.join() 会壅闭主线程,直到 t 所表现的线程实验完成。
- join 是线程同步的一种方式,确保主线程等候子线程完成后再继续实验。
多个线程
可以创建多个线程来实验差别的任务。每个线程都会实验一个独立的任务。- #include <iostream>
- #include <thread>
- void print_hello() {
- std::cout << "Hello from thread!" << std::endl;
- }
- void print_world() {
- std::cout << "World from thread!" << std::endl;
- }
- int main() {
- std::thread t1(print_hello);
- std::thread t2(print_world);
- t1.join();
- t2.join();
- return 0;
- }
复制代码
- t1 和 t2 是两个差别的线程,它们分别实验 print_hello 和 print_world 函数。
- join() 确保在步调竣事之前,全部线程都完成。
线程的分离
除了 join,尚有 detach 函数。利用 detach 后,线程将独立于主线程实验,它不会被等候完成,主线程可以继续实验。- #include <iostream>
- #include <thread>
- void print_message() {
- std::cout << "Message from detached thread!" << std::endl;
- }
- int main() {
- std::thread t(print_message);
- t.detach(); // 分离线程,主线程继续执行
- std::cout << "Main thread continues!" << std::endl;
- // 注意:如果主线程结束,分离线程可能未执行完成
- return 0;
- }
复制代码 留意:
- 利用 detach 后,线程在背景实验,主线程可以退出,不会等候它的完成。若主线程竣事时子线程仍在运行,则大概会出现未界说的举动,因此要鉴戒利用 detach。
线程同步
多线程编程常常面临多个线程共享资源的环境。假如多个线程同时访问和修改共享数据,就会引发数据竞争标题。这时,须要对共享资源举行同步。
互斥量(Mutex)
互斥量是掩护共享资源的一种机制,它确保同一时间只有一个线程能访问共享资源。- #include <iostream>
- #include <thread>
- #include <mutex>
- std::mutex mtx; // 互斥量
- void print_message(const std::string &message) {
- mtx.lock(); // 上锁
- std::cout << message << std::endl;
- mtx.unlock(); // 解锁
- }
- int main() {
- std::thread t1(print_message, "Hello from thread 1");
- std::thread t2(print_message, "Hello from thread 2");
- t1.join();
- t2.join();
- return 0;
- }
复制代码
- std::mutex mtx 界说了一个互斥量,用来掩护共享资源(此处是 std::cout)。
- mtx.lock() 获取锁,确保当火线程独占对 cout 的访问。
- mtx.unlock() 开释锁,允许其他线程获取锁。
std::lock_guard 和 std::unique_lock
为了制止手动调用 lock() 和 unlock(),C++ 提供了 std::lock_guard 和 std::unique_lock,它们在作用域竣事时自动开释锁,制止忘记解锁。- #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;
- // 自动解锁,当 lock_guard 对象超出作用域时
- }
- int main() {
- std::thread t1(print_message, "Hello from thread 1");
- std::thread t2(print_message, "Hello from thread 2");
- t1.join();
- t2.join();
- return 0;
- }
复制代码
- std::lock_guard 自动获取和开释锁,使代码更加轻便安全。
std::condition_variable
std::condition_variable 用于在多个线程之间同步,通常用于实现线程之间的等候与关照机制。- #include <iostream>
- #include <thread>
- #include <mutex>
- #include <condition_variable>
- std::mutex mtx;
- std::condition_variable cv;
- bool ready = false;
- void print_id(int id) {
- std::unique_lock<std::mutex> lck(mtx);
- while (!ready) cv.wait(lck); // 等待条件满足
- std::cout << "Thread " << id << std::endl;
- }
- void go() {
- std::unique_lock<std::mutex> lck(mtx);
- ready = true; // 改变条件
- cv.notify_all(); // 通知所有线程
- }
- int main() {
- std::thread threads[10];
- for (int i = 0; i < 10; ++i)
- threads[i] = std::thread(print_id, i);
- std::cout << "Waiting for threads to be ready..." << std::endl;
- go(); // 通知线程
- for (auto& th : threads) th.join();
- return 0;
- }
复制代码
- cv.wait(lck) 会使当火线程等候直到 ready 为 true。
- cv.notify_all() 会关照全部等候的线程继续实验。
原子利用
原子利用是不会被克制的利用,它对于多线程同步非常有用。在 C++11 中,std::atomic 提供了对根本数据范例的原子利用支持。- #include <iostream>
- #include <thread>
- #include <atomic>
- std::atomic<int> counter(0);
- void increment() {
- for (int i = 0; i < 1000; ++i)
- ++counter; // 原子增加
- }
- int main() {
- std::thread t1(increment);
- std::thread t2(increment);
- t1.join();
- t2.join();
- std::cout << "Final counter value: " << counter.load() << std::endl;
- return 0;
- }
复制代码
- std::atomic 确保对 counter 的利用是原子的,不会被多个线程同时修改,制止了数据竞争。
|