C++中的多线程编程和锁机制

二、多线程、锁

2.1 C语言线程库pthread(POSIX threads)

2.2.1 线程创建 pthread_create
cpp 复制代码
#include <pthread.h>

pthread_t thread;
ThreadData args = {1, "Hello from parameterized thread"};
int result = pthread_create(&thread, attr, function, args);		// 线程创建即启动。
  • arttr:定制各种不同的线程属性,通常直接设为NULL;
  • function:线程要执行的函数;
  • args:函数执行需要输入的参数,无参数是输入NULL,有参数时需要输入ThreadData结构体对象。
  • 返回值:成返回0,失败返回非0值。
2.2.2 线程同步
  • 互斥锁:pthread_mutex_t

    c++ 复制代码
    // 静态初始化互斥锁
    pthread_mutex_t m_mutex = PTHREAD_MUTEX_INITIALIZER;
    // 动态初始化互斥锁
    pthread_mutex_t m_mutex;
    pthread_mutex_init(&m_mutex, nullptr);
    // 加锁
    pthread_mutex_lock(&m_mutex);
    // 解锁
    pthread_mutex_unlock(&m_mutex);
    // 销毁
    pthread_mutex_destroy(&m_mutex);
  • 条件变量:pthread_cond_t

    cpp 复制代码
    // 静态初始化条件变量
    pthread_cond_t m_cond = PTHREAD_COND_INITIALIZER;
    // 动态初始化条件变量
    pthread_cond_t m_cond;
    pthread_cond_init(&m_cond, nullptr);
    // 阻塞
    pthread_cond_Wait(&m_cond, &m_mutex);	// 要同时输入一个互斥锁对象,代表是等待申请该互斥锁
    // 唤醒一个其他等待线程
    pthread_cond_signal(&m_mcond);
    // 唤醒全部其他等待线程
    pthread_cond_broadcast(&m_mcond);
2.2.3 等待线程结束 pthread_join
cpp 复制代码
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
  • thread:要等待结束的线程;
  • retval:若不为NULL,则用于复制出线程的退出状态;
  • 返回值:成功返回0,失败返回非0。
2.2.4 线程分离 pthread_detach
cpp 复制代码
#include <pthread.h>
int pthread_detach(pthread_t thread);
  • thread:要分离的线程;
  • 返回值:成功返回0,失败返回非0。
2.2.5 线程退出 pthread_exit
cpp 复制代码
#include <pthread.h>
void pthread_exit(void *retval);
  • retval:用于保存线程的退出状态;

2.2 C+11标准库的线程 std::thread

2.2.1 线程创建 std::thread
cpp 复制代码
#include <thread>
// 使用函数
std::thread t(func, args1, std::ref(args2), std::cref(args3));		// 线程创建即启动。
// 使用lambda表达式
std::thread t([]() { std::cout << "hellow, world!" << std::endl;});  // 线程创建即启动。
// 使用类成员函数
std::thread t(&MyClass::func, &obj, args1, args2, ...);		// obj是实际依托的对象
// 使用类静态成员函数不需要传递对象
std::thread t(&MyClass::func, args1, args2, ...);	
  • std::ref():指传递引用参数;
  • std::cref():指传递常量引用参数。
2.2.2 线程同步
  • **互斥锁: std::mutex **

    cpp 复制代码
    #include <mutex>
    // 初始化
    std::mutex m_mtx;
    // 加锁
    m_mtx.lock();
    // 解锁
    m_mtx.unlock();
  • **RAII(资源获取即初始化)锁: std::lock_guard **

    用于管理某个锁(Lock)对象 ,因此与 Mutex RAII 相关,方便线程对互斥量上锁,即在某个 lock_guard 对象的声明周期内,它所管理的锁对象会一直保持上锁状态;而 lock_guard 的生命周期结束之后,它所管理的锁对象会自动解锁 (注:类似 shared_ptr 等智能指针管理动态分配的内存资源 )。

    lock_guard 对象不负责管理 Mutex 对象的生命周期,只是简化了 Mutex 对象的上锁和解锁操作

    简单理解就是自动unlock

    c++ 复制代码
    #include<mutex>
    // 初始化
    std::mutex m_mtx;
    
    void func() {
    	std::lock_guard<std::mutex> lc(m_mtx);		// 加锁
    	...
    }
    // 函数执行完毕lc资源释放后会自动解锁,无需显式的unlock
  • **RAII锁: std::unique_lock **

    更灵活的锁,它允许手动锁定和解锁互斥量 ,以及与条件变量一起使用(是lock_guard的进阶版)。与 lock_guard 类似,unique_lock 也是一个 RAII 风格的锁,当对象离开作用域时,它会自动解锁互斥量。unique_lock 还支持延迟锁定、尝试锁定和可转移的锁所有权

    cpp 复制代码
    #include<mutex>
    // 初始化
    std::mutex m_mtx;
    
    void func() {
    	std::unique_lock<std::mutex> lc(m_mtx);		// 加锁
    	...
    }
    // 函数执行完毕lc资源释放后会自动解锁,无需显式的unlock
  • 条件变量:std::condition_variable

    cpp 复制代码
    #include <condition_variable>
    #include <mutex>
    
    std::mutex m_mtx;
    std::unique_lock<std::mutex> lc(m_mtx);
        
    // 初始化 
    std::condition_variable cv;
    // 阻塞
    cv.wait(lc);
    // 唤醒一个阻塞线程
    cv.notify_one();
    // 唤醒全部阻塞线程
    cv.notify_all();
2.2.3 等待线程结束 thread.join()
cpp 复制代码
#include <thread>

std::thread t(func);
t.join();	// 等待线程结束
2.2.4 线程分离 thread.detach()
复制代码
#include <thread>

std::thread t(func);
t.detach();	// 等待线程结束
2.2.5 线程退出

C++标准库std::thread并没有提供类似pthread_exit函数相关显式退出线程的函数,原因是 std::thread 的设计是面向 RAII(Resource Acquisition Is Initialization)原则的,即资源管理应当通过对象的生命周期来控制。

尽管没有 pthread_exit,你仍然可以通过控制线程的执行逻辑来实现类似的功能。如,通过在线程函数中检查某个退出条件或标志位,在满足条件时退出函数。

cpp 复制代码
#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>

std::atomic<bool> stop_thread(false);

void worker() {
    while (!stop_thread) {
        std::cout << "Working..." << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
    std::cout << "Worker thread is exiting..." << std::endl;
}

int main() {
    std::thread t(worker);
    std::this_thread::sleep_for(std::chrono::seconds(2));
    stop_thread = true;  // Signal the thread to exit
    t.join();
    std::cout << "Main thread is done." << std::endl;
    return 0;
}
相关推荐
沐知全栈开发3 小时前
HTML DOM 修改
开发语言
赖small强4 小时前
【Linux驱动开发】Linux SDIO 底层原理与实现细节详解
linux·驱动开发·sdio
2501_941236214 小时前
C++与Node.js集成
开发语言·c++·算法
晨非辰5 小时前
【数据结构初阶系列】归并排序全透视:从算法原理全分析到源码实战应用
运维·c语言·数据结构·c++·人工智能·python·深度学习
菠菠萝宝6 小时前
【Java手搓RAGFlow】-3- 用户认证与权限管理
java·开发语言·人工智能·llm·openai·qwen·rag
llxxyy卢7 小时前
通关upload-labs(14-21)加分析源码
linux·运维·服务器
csdn_wuwt7 小时前
前后端中Dto是什么意思?
开发语言·网络·后端·安全·前端框架·开发
print(未来)8 小时前
C++ 与 C# 的性能比较:选择合适的语言进行高效开发
java·开发语言
四问四不知8 小时前
Rust语言入门
开发语言·rust
JosieBook8 小时前
【Rust】 基于Rust 从零构建一个本地 RSS 阅读器
开发语言·后端·rust