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;
}
相关推荐
神奇夜光杯5 分钟前
Python酷库之旅-第三方库Pandas(202)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长
筱源源7 分钟前
Kafka-linux环境部署
linux·kafka
Themberfue7 分钟前
Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
java·开发语言·线程·多线程·synchronized·
plmm烟酒僧9 分钟前
Windows下QT调用MinGW编译的OpenCV
开发语言·windows·qt·opencv
测试界的酸菜鱼21 分钟前
Python 大数据展示屏实例
大数据·开发语言·python
我是谁??21 分钟前
C/C++使用AddressSanitizer检测内存错误
c语言·c++
晨曦_子画30 分钟前
编程语言之战:AI 之后的 Kotlin 与 Java
android·java·开发语言·人工智能·kotlin
Black_Friend38 分钟前
关于在VS中使用Qt不同版本报错的问题
开发语言·qt
算法与编程之美1 小时前
文件的写入与读取
linux·运维·服务器
发霉的闲鱼1 小时前
MFC 重写了listControl类(类名为A),并把双击事件的处理函数定义在A中,主窗口如何接收表格是否被双击
c++·mfc