C++98/11 多线程与高并发

基本概念:

并发:两个或多个任务同时进行;一个程序同时执行多个独立的任务

并发的假象:cpu的上下文切换

使用并发的原因:同时干多件事,提高效率

可执行文件:.exe文件,可以在Windows下运行,Linux下,./文件名;

进程:一个可执行文件运行起来了,即创建进程

线程:每个进程,都有一个主线程,这个主线程唯一的,也就是一个进程中只有一个主线程,进程运行起来,主线程也运行起来

线程:用来执行代码的,一条代码的执行(通路)道路;除了主线程外,可以创建其他线程,每创建一个线程,在同一时刻就可以多干一件事

线程并非越多越好,每开辟一个线程,都需要有一个独立的堆栈空间(1M),线程切换会耗费时间

并发的实现:两个或多个任务同时发生

实现并发的手段:1.多个进程实现并发

                          2.单个进程中创建多个线程实现并发

多进程并发:多个进程同时执行

进程之间的通信:同一台电脑上:管道,文件,共享内存,消息队列

不同电脑:socket通信技术

多线程并发:单个进程中,创建多个线程

线程:轻量级进程,同一个进程中,所有线程共享内存,,所以线程开销远小于进程,但是带来内存数据不一致问题

线程启动:

join()函数:主线程阻塞,等待子线程执行完,当子线程执行完毕,主线程继续执行,直到结束

detach()函数:主线程与子线程同时执行,子线程就会驻留在后台运行,被C++运行时库接管,当子线程执行完毕,运行时库处理该线程相关资源(守护进程)

一旦调用detach(),就不能再用join()

joinable():判断是否成功使用join()或detach(),成功返回true

其他创建线程方法:用类对象(可调用对象)

一旦调用detach(),主线程结束,创建的对象也不在了,但是复制的对象在子线程中依然存在,只要不是指针,引用,就不会产生问题

传递临时对象作为参数:char字符数组作为参数时,转为string对象;只要用临时构造的类对象作为参数传递给线程,那么就一定能在主线程执行完毕时把参数传给线程,保证子线程的执行

如果传递对象,避免隐式转换,建议用引用来接

若传递int这种简单的类型,建议用值传递

建议不使用detach(),用join()避免局部变量失效导致线程对内存的非法引用

线程ID:一个线程只有一个id,std::this_thread::get_id()获取线程id函数

传递类对象、智能指针作为线程参数:引用std::ref() == &;

创建和等待多个线程:多个线程的执行顺序是乱的,跟操作系统内部对线程的调度有关

主线程等待子线程全部结束,最后主线程结束,用join()

数据共享问题分析:只读的数据是安全的,有读有写的数据没有特别处理,程序一定崩溃

互斥量:类对象,多线程尝试用lock()加锁,只有一个线程能锁住成功,如果没锁成功,那么流程卡在lock()不断尝试去锁

先lock(),操作共享数据,再unlock()

lock()与unlock()成对使用

std::lock_guard类模板可以避免忘记unlock()而自动解锁(一旦使用lock_guard(),unlock()和lock()都不能使用)

lock_guard(),在构造函数中执行mutex::lock(),在析构函数中执行mutex::unlock()

死锁:线程A执行时,先加金锁,再加银锁

         线程B执行时,先加银锁,,再去要金锁

线程A在等银锁,线程B在等金锁,因此产生死锁

死锁解决方案:保证互斥量上锁的顺序一致就不会产生死锁

std::lock()函数模板:用来处理多个互斥量,一次锁住两个或两个以上的互斥量,不会产生因为锁的顺序产生死锁问题,要么两个都锁住,要么都不锁,如果只锁住一个,则立即解锁

std::lock_guard<std::mutex> 名称(my_mutex,std::adopt_lock)不需要手动解锁

unique_lock类模板:用法上比lock_guard()灵活,但是效率差一点,占用内存多一点

std::adopt_lock(),表示已经被lock(),所以使用前先lock()

std::try_to_lock():尝试用lock()去锁定mutex,但如果没有锁成功,就会返回,不会阻塞在那,前提是不能用lock()

std::defer_lock():初始化了一个没有加锁的mutex

std::defer_lock()成员函数:release()使unique_lock()与mutex分离,需要自己负责mutex的unlock()

锁住代码的多少称为粒度,选择合适的粒度,能够提高运行效率

单例模式:整个项目中,某个或某些对象只能创建一个

单例设计模式共享数据问题分析:如何在我们自己创建的线程中而不是主线程中创建一个单例类对象

两个线程同一入口函数,并行执行时,两个线程会不定时交替执行,用互斥量或std::call_once()解决

std::call_once():能够保证函数()只被调用一次,具有互斥这种能力且消耗资源比互斥量少

该函数std::call_once()调用一次之后就会被标记"已调用"状态

条件变量:std::condition_variable类,生成一个条件变量对象和互斥量配合使用 、

wait()用来等一个东西,如果第二个lambda表达式参数为false,阻塞直到其他某个线程调用notify_one()成员函数为止;如果第二个lambda表达式参数为true,wait()直接返回;如果没有第二个参数和lambda表达式为false一样

notify_one():通知一个线程;其他线程调用此函数将wait(原来睡着/阻塞)的状态唤醒,wait()不断尝试获取互斥量锁,如果获取不到,那么流程就卡在wait()

notify_all():尝试把wait()线程唤醒

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值