首页 > 编程语言 >C++中的多线程编程和锁机制

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

时间:2024-08-18 23:23:23浏览次数:16  
标签:std include thread 编程 C++ 线程 pthread mutex 多线程

二、多线程、锁

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;
}

标签:std,include,thread,编程,C++,线程,pthread,mutex,多线程
From: https://blog.csdn.net/shenfenxihuan/article/details/141286597

相关文章

  • 关于c++使用toml plusplus(俗称toml++)的使用(2)
    链接toml++-githubtoml++-帮助文档使用要求:c++17及以上版本toml语法-英文toml语法-中文toml读取参见官方给出的范例toml写入目标目标:数组表的写入目标文件内容如下[NET_INTERFACE]bool=falseinteger=1234567890string='thisisastring'[[f......
  • Scratch多人协作:共创编程乐园
    标题:Scratch多人协作:共创编程乐园在Scratch这个充满创意的编程乐园中,多人协作不仅能激发团队的创造力,还能提高项目的完成效率。本文将详细介绍如何在Scratch中实现多人协作,包括共享工作室、使用云变量、以及一些实用的扩展工具和技巧。在Scratch这个充满创意的编程乐园中,......
  • C++:新枚举与新结构
    一、枚举(一)C枚举?真整数!    考虑下面的程序#include<stdio.h>#include<stdlib.h>typedefenum{spring,summer,autumn,winter}Season;voidprintSeason(Seasonseason){ switch(season){ casespring: printf("spring"); break; case......
  • C++:从Type到Control
    一、基本数据类型     计算机的存储空间由最基本的二进制数(比特)组成,若干连续的二进制位(一般为8位)组成一个字节并被分配一个内存地址(),所以单独的比特没有地址,通常情况下CPU也不会一个比特一个比特读取数据,相反,字节被当作基本操作单位。在此前提下,一切要存储在计算机上的......
  • C++:函数
         FunctionsareC++entitiesthatassociateasequenceofstatements(afunctionbody)withanameandalistofzeroormorefunctionparameters.        函数是C++中的实体,它将一系列语句(一个函数体)与一个名称和零个或多个函数参数列表相关......
  • 关于c++使用toml plusplus(俗称toml++)的使用
    链接toml++-githubtoml++-帮助文档使用要求:c++17及以上版本toml语法-英文toml语法-中文toml读取参见官方给出的范例toml写入一个范例,一个开胃菜toml文件待生成的目标文件内容为[NET_INTERFACE]bool=falseinteger=1234567890string='thisis......
  • Linux, shell编程备份数据库详解,带你读懂命令行指令
    目录先看最终代码再解释[!-d"${BACKUP}/${DATETIME}"]解析mysqldump-u${DB_USER}-p${DB_PW}--host=${HOST}-q-R--databases${DATABASE}|gzip>${BACKUP}/${DATETIME}/$DATETIME.sql.gz解析 tar-zcvf$DATETIME.tar.gz${DATETIME}解析先看最终代码再解......
  • 以c primer plus(第六版)为大纲的C语言初学手记,含示例代码及编程练习(第四章)
    //第4章//example4.1//#include<stdio.h>//#include<string.h> //toincludestrlrn()//#defineDENSITY62.4 //todefineaconstant//intmain()//{//   floatweight,volume;//   intsize,letters;//   charname[40]; //todeclareadig......
  • 【C++学习笔记 18】C++中的隐式构造函数
    举个例子#include<iostream>#include<string>usingString=std::string;classEntity{private: Stringm_Name; intm_Age;public: Entity(constString&name) :m_Name(name),m_Age(-1){} Entity(intage) :m_Name("UnKnown")......
  • C语言编程-GCC编译过程
    gcc编译预处理->编译->汇编->链接预处理gcc-Ehelloworld.c-ohelloworld.i头文件展开;不检查语法错误,即可以展开任意文件;宏定义替换;将宏名替换为宏值;替换注释;将注释替换为空行;展开条件编译;根据条件来展开指令;编译gcc-Shelloworld.i-ohelloworld.s逐行检查......