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

二、多线程、锁

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

2.2.1 线程创建 pthread_create
#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

    // 静态初始化互斥锁
    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

    // 静态初始化条件变量
    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
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
  • thread:要等待结束的线程;
  • retval:若不为NULL,则用于复制出线程的退出状态;
  • 返回值:成功返回0,失败返回非0。
2.2.4 线程分离 pthread_detach
#include <pthread.h>
int pthread_detach(pthread_t thread);
  • thread:要分离的线程;
  • 返回值:成功返回0,失败返回非0。
2.2.5 线程退出 pthread_exit
#include <pthread.h>
void pthread_exit(void *retval);
  • retval:用于保存线程的退出状态;

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

2.2.1 线程创建 std::thread
#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 **

    #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

    #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 还支持延迟锁定、尝试锁定和可转移的锁所有权

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

    #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()
#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,你仍然可以通过控制线程的执行逻辑来实现类似的功能。如,通过在线程函数中检查某个退出条件或标志位,在满足条件时退出函数。

#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;
}
  • 22
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值