当前位置: 首页 > article >正文

C++ 之多线程相关总结

C++ 之多线程相关总结

1.多线程相关基础知识

1.1 线程的创建和管理

1. std::thread 类:

用于创建和管理线程。通过将可调用对象(如函数、函数对象、lambda 表达式)作为参数传递给 std::thread 的构造函数,可以创建一个新的线程。

  • join() 方法会阻塞当前线程,直到被调用的线程执行完毕。如果不调用 join()detach(),程序会在 std::thread 对象析构时终止程序,因为会调用 std::terminate()
  • detach() 方法允许线程独立运行,与主线程分离,不再被 std::thread 对象管理,它会继续在后台执行直至完成或程序结束。
#include <iostream>
#include <thread>

void threadFunction() {
    std::cout << "Thread function running." << std::endl;
}

int main() {
    std::thread t(threadFunction); // 创建一个新的线程,执行 threadFunction
    t.join(); // 等待线程结束
    return 0;
}
2. 线程函数:

可以是普通函数、成员函数、函数对象或 lambda 表达式。

#include <iostream>
#include <thread>

class MyClass {
public:
    void memberFunction() {
        std::cout << "Member function running in thread." << std::endl;
    }
};

int main() {
    MyClass obj;
    std::thread t(&MyClass::memberFunction, &obj); // 调用成员函数
    t.join();
    return 0;
}

1.2 线程同步

1.互斥量(Mutex):
  • std::mutex 提供了基本的互斥机制,用于保护共享数据,防止多个线程同时访问。
#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

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

int main() {
    std::thread t1(printMessage, "Hello from thread 1");
    std::thread t2(printMessage, "Hello from thread 2");
    t1.join();
    t2.join();
    return 0;
}
  • std::lock_guard 是一个 RAII 类,在构造时自动锁定互斥量,在析构时自动解锁,确保正确的锁定和解锁操作。
  • std::unique_lock 提供了更灵活的锁定方式,可以手动加锁、解锁,支持延迟锁定和所有权转移。
2.条件变量(Condition Variables):
  • std::condition_variable 允许线程等待某些条件的发生。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>

std::mutex mtx;
std::condition_variable cv;
std::queue<int> dataQueue;

void producer() {
    for (int i = 0; i < 10; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        std::unique_lock<std::mutex> lock(mtx);
        dataQueue.push(i);
        std::cout << "Produced: " << i << std::endl;
        cv.notify_one(); // 通知一个等待的线程
    }
}

void consumer() {
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, []{ return!dataQueue.empty(); }); // 等待条件满足
        int data = dataQueue.front();
        dataQueue.pop();
        lock.unlock();
        std::cout << "Consumed: " << data << std::endl;
        if (data == 9) break;
    }
}

int main() {
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join();
    t2.join();
    return 0;
}
  • cv.wait() 会释放锁并等待条件变量被通知,一旦收到通知,它会重新获取锁。
3. 原子操作
  • 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 << "Counter value: " << counter << std::endl;
    return 0;
}

1.3 线程间通信

1.共享数据:
  • 多个线程可以通过共享数据进行通信,但需要使用互斥量或其他同步机制来保护数据。
  • 避免死锁,如避免多个线程以不同顺序获取多个锁。
2.消息传递:
  • 使用 std::promisestd::future 可以实现线程间的单向消息传递。
#include <iostream>
#include <thread>
#include <future>

int factorial(int n) {
    int result = 1;
    for (int i = 1; i <= n; ++i) {
        result *= i;
    }
    return result;
}

int main() {
    std::promise<int> prom;
    std::future<int> fut = prom.get_future();

    std::thread t([&prom]() {
        int result = factorial(5);
        prom.set_value(result);
    });

    std::cout << "Factorial result: " << fut.get() << std::endl;
    t.join();
    return 0;
}

1.4 高级线程工具

1. std::async 和 std::future:
  • std::async 可以异步执行函数,并返回一个 std::future 对象。
#include <iostream>
#include <future>

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

int main() {
    std::future<int> result = std::async(std::launch::async, add, 3, 4);
    std::cout << "Sum: " << result.get() << std::endl;
    return 0;
}
  • std::launch::async 表示函数会在另一个线程中立即执行,std::launch::deferred 表示延迟执行,直到调用 get() 时才在调用线程中执行。
2. std::packaged_task:
  • 包装可调用对象,允许将其作为任务传递,并通过 std::future 获取结果。
#include <iostream>
#include <thread>
#include <future>

int main() {
    std::packaged_task<int(int, int)> task(add);
    std::future<int> result = task.get_future();
    std::thread t(std::move(task), 3, 4);
    std::cout << "Sum: " << result.get() << std::endl;
    t.join();
    return 0;
}

2. 线程的使用:创建及管理

1.类内创建线程

  • 可以通过成员函数或者析构函数初始化或者创建线程,通过析构函数关闭/销毁线程
#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>

class ThreadedClass {
private:
    std::thread workerThread;
    std::atomic<bool> stopFlag;

    // 线程函数
    void workerFunction() {
        while (!stopFlag) {
            std::cout << "Thread is running..." << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
        std::cout << "Thread is stopping..." << std::endl;
    }
public:
    ThreadedClass() : stopFlag(false) {
        // 启动线程
        workerThread = std::thread(&ThreadedClass::workerFunction, this);
    }

    ~ThreadedClass() {
        // 设置停止标志
        stopFlag = true;
        if (workerThread.joinable()) {
            // 等待线程结束
            workerThread.join();
        }
    }
};

int main() {
    ThreadedClass obj;
    // 让程序运行一段时间,以便观察线程的行为
    std::this_thread::sleep_for(std::chrono::seconds(5));
    return 0;
}

2. 函数内部创建线程

  • 单独执行某个函数或者某个类的成员函数
#include <iostream>
#include <thread>
#include <chrono>

class MyClass {
public:
    // 类中的函数,将在新线程中执行
    void classFunction() {
        for (int i = 0; i < 5; ++i) {
            std::cout << "Class function running, iteration: " << i << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
};

// 主函数,在其中创建线程执行类的函数
void mainFunction() {
    std::cout << "Main function starts." << std::endl;
    MyClass obj;

    // 创建一个新线程执行类的成员函数
    std::thread t(&MyClass::classFunction, &obj);

    // 主线程继续执行自己的任务
    for (int i = 0; i < 3; ++i) {
        std::cout << "Main function running, iteration: " << i << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    // 等待新线程执行完毕
    t.join();

    std::cout << "Main function ends." << std::endl;
}

// 函数将在新线程中执行
void newThreadFunction() {
    for (int i = 0; i < 5; ++i) {
        std::cout << "New thread: " << i << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}



int main() {
    mainFunction();

    //or
    // 创建一个新线程
    std::thread newThread(newThreadFunction);

    // 主线程继续执行自己的任务
    for (int i = 0; i < 3; ++i) {
        std::cout << "Main thread: " << i << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    // 等待新线程执行完成
    newThread.join();

    return 0;
}

----更新中。。。。。


http://www.kler.cn/a/508100.html

相关文章:

  • ICC和GCC编译器编译Openmp程序的运行区别
  • 28:CAN总线入门一:CAN的基本介绍
  • 如何在Mac上使用Brew更新Cursor应用程序
  • 运行fastGPT 第四步 配置ONE API 添加模型
  • Linux内核的启动
  • 少一点If/Else - 状态模式(State Pattern)
  • [深度学习]神经网络线性回归简易实例
  • 数据结构与算法学习笔记----中国剩余定理
  • GaussDB创建不同兼容模式的数据库
  • MMDetection学习系列(4)——Cascade R-CNN深度探索与实战指南
  • 进程的家园:探索 Linux 地址空间的奥秘
  • 多线程进阶-线程安全的集合类
  • 游戏如何检测Xposed框架
  • C#实例化类,当类名和方法一样或者不一样时运行流程
  • 【达梦数据库(Oracle模式)】如何将视图中的数据导出
  • Python 爬虫学习指南与资料分享
  • rsync结合inotify实现文件实时同步
  • Lua项目下SSRF利用Redis文件覆盖lua回显RCE
  • 人工智能之深度学习_[3] -PyTorch自动微分模块和构建线性回归模型
  • 1.1初探大模型:起源与发展
  • 如何将数据库字符集改为中文,让今后所有的数据库都支持中文
  • 二十三种设计模式-代理模式
  • IF=24.5! 综述:机器人纹理识别触觉感知和机器学习进展
  • 请求响应-
  • 【算法】差分
  • python爬取Boss直聘,分析北京招聘市场