c++多线程编程

打印 上一主题 下一主题

主题 899|帖子 899|积分 2697

c++线程库:

创建线程:需要可调用的函数或者函数对象作为线程入口点

  1.     例:std::thread threadname ( function_name , args...)   
复制代码

  • 在C++中,当使用std::thread创建线程并传递类的成员函数时,需要使用&来获取成员函数的地址,同时还需要传递对象的指针(或引用)作为第一个参数。
例:(A为一个类,a为A的一个实例化对象) thread t (&A::func_name,&a,args)
增补:在使用多线程编程时,内存管理变得更加复杂,使用智能指针可以帮助我们更好避免内存泄漏

auto_ptr 是c++ 98定义的智能指针模板,其定义了管理指针的对象,可以将new 得到(直接或间接)的地址赋给这种对象。当对象过期时,其析构函数将使用delete 来开释内存
头文件:#include < memory >  

  • 【c++11已过期】auto_ptr 变量名(new 类型)

     ·ptr.get()    //获取智能指针托管的指针地址
     ·ptr.release()  //取消智能指针对动态内存的托管
     ·ptr.reset(arg)  //将参数的指针(不指定则为NULL),与托管的指针比较,假如地址不一致,那么就会析构掉原来托管的指针,然后使用参数的指针替换之


  • auto_ptr 主要有三大问题:
     · 复制和赋值会改变资源的全部权,不符合人的直觉。
     · 在 STL 容器中使用auto_ptr存在风险,因为容器内的元素必需支持可复制和可赋值。
     · 不支持对象数组的操纵
因此c++11后使用unique_ptr shared_ptr和weak_ptr取代

  • unique_ptr
函数:

  1.     thread.join();      //执行join后,等待线程完成函数,主线程需要等待子线程运行结束了才可以结束
  2.    
  3.     thread.detach();    //执行detach可以分离子线程,主线程不会等待子线程运行结束才结束
  4.    
  5.     thread.joinable();  //会返回一个bool值,判断是否已经使用过join或者detach *已调用时返回false*
  6.    
  7.     std::ref(para);         //thread的方法传递引用的时候,必须外层用ref来进行引用传递,否则会编译出错
复制代码
调用类内私有成员函数:友元函数

例: void func_name();需要调用类内的私有成员函数
则在类内需要通过声明 friend void func_name();
c++11 互斥量


  • 头文件:#include

  • 根本互斥类: mutex _name;

    • 构造函数:mutex不允许拷贝构造,也不允许move拷贝,最初产生的mutex对象处于unlocked状态
    • lock():调用线程将锁住该互斥量,线程调用该函数会发生以下3种环境:
      (1) 假如该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用unlock之前,该线程一直拥有该锁。
      (2) 假如当前互斥量被其他线程锁住,则当前的调用线程被壅闭住。
      (3) 假如当前互斥量被当前调用线程锁住,则会产生死锁,,也就是说同一个线程中不允许锁两次。
    • try_lock():尝试锁住互斥量,假如互斥量被其他线程占有,则当前线程也不会被壅闭,线程调用该函数会出现下面3种环境:
      (1) 假如当前互斥量没有被其他线程占有,则该线程锁住互斥量,直到该线程调用unlock开释互斥量。
      (2) 假如当前互斥量被其他线程锁住,则当前调用线程返回false,而并不会被壅闭掉。
      (3) 假如当前互斥量被当前调用线程锁住,则会产生死锁。

  • 递归互斥类【能进行多次锁定而不造成死锁】: recursive_mutex

    • 与mutex类似,但是能够进行多次lock,能够规避一些死锁问题

  • 定时互斥类【可以锁定一定的时间】:time_mutex
  • 定时递归互斥类:recursive_timed_mutex;
互斥量死锁


  • lock_guard: c++标准库互斥量封装类,用于掩护共享数据,防止多个线程同时访问统一资源而导致的数据竞争

    • 构造函数调用时,该互斥量主动锁定
    • 析构函数调用时,该互斥量主动解锁

例:lock_guard< Template > lock_name(obj);


  • lock_guard类是 non-copyable的。

  • unique_lock: 可以对互斥量进行更加灵活管理,包罗延迟加锁、条件变量、超时等

    • 成员函数:
      (1) lock()   尝试对互斥量加锁,若加锁失败则壅闭直到乐成加锁
      (2) try_lock()     尝试枷锁,乐成返回true,失败返回false

condition_variable及其使用场景


  • 头文件#include
  • 条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包罗两个动作:一个线程等待条件变量的条件成立而挂起;另一个线程使条件成立(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥量结合在一起。【常见用途:生产者-消费者模型】
  • 从条件变量的作用可以知道,在使用条件变量时,分为两个方面:
    (1) 用于关照已壅闭线程,共享变量已改变
    (2) 用于壅闭某一线程,直至该线程被唤醒

  • 创建:condition_variable cv_name;
  • cv_obj.wait(unique_lock_obj,arg) 消费者在共享资源不足时,通过wait函数等待,第二个参数arg为true时不等待,false时壅闭等待。
当前线程调用wait()后将被壅闭,直到别的某个线程调用notify_唤醒当前线程;当线程被壅闭时,该函数会主动调用std::mutex的unlock()开释锁,使得其它被壅闭在锁竞争上的线程得以继续执行。一旦当前线程得到关照(notify,通常是别的某个线程调用notify_唤醒了当前线程),wait()函数也是主动调用std::mutex的lock()。wait分为无条件被壅闭和带条件的被壅闭两种。

  • cv_obj.notify_one()  唤醒某个等待(wait)线程。假如当前没有等待线程,则该函数什么也不做,假如同时存在多个等待线程,则唤醒某个线程是不确定的
  • cv_obj.notify_all() 唤醒全部等待进程
  • notify_all_at_thread_exit 当调用该函数的线程退出时,全部在 cond 条件变量上等待的线程都会收到关照
condition_variable_any 先容
与 condition_variable 类似,只不过 condition_variable_any 的 wait 函数可以接受任何 lockable 参数,而condition_variable 只能接受 unique_lock< mutex > 类型的参数,除此以外,和 :condition_variable 几乎完全一样。
异步并发

1. async、future

  • 头文件: #include
  • c++11引入的函数模板,用于异步执行一个函数,并返回到future对象,表示异步操纵的结果。使用async可以方便进行异步编程,避免了手动创建和管理线程的麻烦
例:std::future< template > future_name = std::async(std::launch::async, func_name);
2. packaged_task

  • 类模板,用于将一个可调用对象(如函数、函数对象或Lambda表达式)封装为一个异步操纵,并返回一个future对象,表示异步操纵结果。package_task可以方便将一个函数或可调用对象转换为一个异步操纵,供其他线程使用
例: std::packaged_task task_name(func_name);
// 此时得到的是封装好的task对象,需要通过创建线程执行 【记得使用move(task)把可移动对象放入线程执行】
auto result = task_name.get_future();
3. promise

  • 用于在线程中产生一个值,并在另一个线程中获取该值。通常与future和async一起使用,实现异步编程。
  • 创建:std::promise name
  • 获取值: name.get_future();+result.get()
原子操纵:atomic


  • c++11标准库中的一个模板类,用于实现多线程编程环境下的原子操纵。提供一种线程安全的方式访问和修改共享变量,可以避免多线程环境中的数据竞争问题
  • 头文件: #include
  • 创建: std::atomic data_name
  • 相较于加锁实现的互斥,在线程安全中,原子操纵的性能更好
  • 常见std::atomic操纵:
    load(): 将std::atomic变量的值加载到当前线程的本地缓存中并返回
    store(value): 将value的值存储到std::atomic变量中,这个操纵是原子性的
    exchange(value): 将value的值存储到std::atomic变量中,并返回原先的值
    compare_exchange_weak(expected, val) 和 compare_exchange_strong(expected, val):比较 std::atomic 变量的值和 expected 的值是否相同,假如相同,则将 val 的值存储到 std::atomic 变量中,并返回 true;否则,将 std::atomic 变量的值存储到 expected 中,并返回 false。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

惊雷无声

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表