c++ 多线程

 

c++ 提供了强大的多线程支持, 通过标准库thread和其他工具, 可以在多核处理器上并行执行多个任务

通过使用多线程, 能够在现代计算机系统中充分利用多核 CPU, 提高程序的执行效率

创建

c++ 提供 std::thread 类来实现线程创建和管理

#include <iostream>
#include <thread>
#include <unistd.h>
#include <cstdlib>

void func_1() {
    for (int i = 0; i < 5; ++i) {
        std::cout << "func_1" << std::endl;
        sleep(1);
    }
}

void func_2() {
    for (int i = 0; i < 10; ++i) {
        std::cout << "func_2" << std::endl;
        sleep(1);
    }
}

int main() {
    // 实例化一个线程对象th1, 使用函数t1构造, 然后该线程就开始执行
    std::thread th1(func_1);
    std::thread th2(func_2);
    // 必须join或detach, 等待子线程结束主进程才可以退出
    th1.join();
    th2.join();
    return 0;
}

运行结果

func_1
func_2
func_1
func_2
func_1
func_2
func_1
func_2
func_1

std::thread 会在构造时启动新线程, 线程会在构造后自动开始执行

join() 是主线程等待子线程执行完毕的方式; 主线程会阻塞, 直到指定的子线程完成

无参数函数

#include <iostream>
#include <thread>

void func() {
    for (int i = 0; i < 10; ++i) {
        std::cout << "func" << std::endl;
    }
}

int main() {
    std::thread t(func);  // 创建线程 t 执行 func 函数
    t.join();  // 等待线程 t 执行完毕
    return 0;
}

std::thread 接受函数指针或可调用对象作为参数, 可以直接传递无参数的函数

含参数函数

#include <iostream>
#include <thread>

void print_num(int i) {
    std::cout << "Received number: " << i << std::endl;
}

int main() {
    int num = 10;
    std::thread t(print_num, num);  // 将参数 num 传递给线程
    t.join();  // 等待线程执行完毕
    return 0;
}

类成员函数

对于类的成员函数, 需要稍微注意传递对象实例和成员函数的指针

可以通过 &object_name 和成员函数指针来指定要调用的成员函数

#include <iostream>
#include <thread>

class Demo {
public:
    void do_lengthy_work(int num) {
        std::cout << "Working on task " << num << std::endl;
    }
};

int main() {
    Demo my_x;  // 创建类的实例
    int num = 5;

    // 使用类成员函数创建线程, 传递实例和参数
    std::thread t(&Demo::do_lengthy_work, &my_x, num);
    t.join();  // 等待线程执行完毕
    return 0;
}

类成员函数需要传递对象实例(&my_x)和成员函数的参数

使用成员函数时, 需要注意实例的生命周期, 确保实例在线程执行过程中仍然有效

同步

join

join() 用于主线程等待子线程完成

当主线程调用 join() 时, 主线程会被阻塞, 直到子线程执行完毕

std::thread t(func);
t.join();  // 主线程等待线程 t 执行完毕

detach

detach() 方法将线程从主线程中分离出来, 线程继续在后台执行

分离的线程会自动在执行完成后释放资源

使用 detach() 时, 线程的生命周期不再由主线程控制, 需要开发者自行保证线程的安全性

std::thread t(func);
t.detach();  // 主线程不等待, 线程在后台执行
  • 示例
#include <iostream>
#include <thread>

void func() {
    std::cout << "Thread started" << std::endl;
    // 模拟任务
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Thread finished" << std::endl;
}

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

    // 选择是否等待子线程执行完毕
    if (/*某种条件*/) {
        t.join();  // 等待线程结束
    } else {
        t.detach();  // 不等待线程结束
    }

    std::cout << "Main thread finished" << std::endl;
    return 0;
}

当线程完成工作时, 它会自动释放系统资源

如果线程在主线程退出之前没有正确结束, 可能会导致资源泄漏,

为了避免资源泄漏, 必须在主线程退出之前使用 join() 或 detach() 确保子线程的资源得到正确释放,