C++_2——thread & Linux多线程

线程的创建、资源回收

#include <thread>
// 构造函数
	// 默认构造
	thread() noexcept;
	// 显式构造:输入重载函数的函数指针,导致编译错误
	template <class Fn, class... Args>
	explicit thread (Fn&& fn, Args&&... args);
#include <thread>

void func1(){}
void func2(int arg){}
void func3(int arg1, int arg2){}

// 创建
std::thread t1(func1);
std::thread t2(func2, 10);
std::thread t3(func3, 10, 20);

// 资源回收
if(t1.joinable())
	t1.join();
if(t2.joinable())
	t2.join();
if(t3.joinable())
	t3.join();

// 线程后台运行,不再受程序控制
std::thread t4(func1);
t4.detach();

摘抄1
在很多情况下,主线程创建并启动子线程,如果子线程中要进行大量的耗时运算,主线程将可能早于子线程结束。如果主线程需要知道子线程的执行结果时,就需要等待子线程执行结束了。主线程可以sleep(xx),但这样的xx时间不好确定,因为子线程的执行时间不确定,join()方法比较合适这个场景。

摘抄2
是主线程等待子线程的终止。也就是说主线程的代码块中,如果碰到了t.join()方法,此时主线程需要等待(阻塞),等待子线程结束了(Waits for this thread to die.),才能继续执行t.join()之后的代码块。

摘抄3
detach调用之后,目标线程就成为了守护线程,驻留后台运行,与之关联的std::thread对象失去对目标线程的关联,无法再通过std::thread对象取得该线程的控制权。当目标线程主函数执行完之后,目标线程就结束了,运行时库负责清理与该线程相关的资源。
当一个thread对象到达生命期终点而关联线程还没有结束时,则thread对象取消与线程之间的关联,目标线程线程则变为分离线程继续运行。
detach使主线程不用等待子线程可以继续往下执行,但即使主线程终止了,子线程也不一定终止。
————————————————
版权声明:本文为CSDN博主「AllenSun-1990」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xikangsoon/article/details/104511675/

线程锁

c++之多线程中“锁”的基本用法

#include <thread>
#include <mutex>

/**************
	std::mutex
	对于非原子操作,多线程访问一个内存变量,任意时刻允许一个线程上锁
	易产生死锁,锁多了较为繁杂
*/
std::mutex mtx;			
mtx.lock()				//上锁失败则阻塞直到成功
mtx.try_lock()			//上锁失败则线程不阻塞
mtx.unlock()

/**************
	std::lock_guard
	构造时,调用传入对象的lock()
	析构时,调用传入对象的unlock()
	解决了死锁的问题
*/	
std::lock_guard<std::mutex> lg(mtx);		//此时调用mtx.lock()
											//当抛出异常或离开lg的作用域,lg被析构之后,调用mtx.unlock()

/**************
	std::uniqu_lock
	以std::lock_guard为基础,更为灵活
*/												
std::unique_lock<std::mutex> ul(mtx)
//提前解锁
ul.unlock()								
//尝试锁,并判断是否锁住
std::uniqu_lock<std::mutex> ul(mtx.std::try_to_lock) 	
ul.owns_lock	//bool量										

线程池

摘抄4
线程池(thread pool):一种线程的使用模式,线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。

本人太菜,写不出来,这里贴几个开源线程池:

  1. https://github.com/kanade2010/ThreadPool
    这个比较简单易懂,应对一般的问题应该够了。
  2. https://github.com/mtrebi/thread-pool
    这个功能比较强大,测试也比较严谨,就是看起来让人头皮发麻。

摘抄5
notify_one()与notify_all()常用来唤醒阻塞的线程。
notify_one():只唤醒等待队列中的第一个线程;不存在锁争用,所以能够立即获得锁。其余的线程不会被唤醒,需要等待再次调用notify_one()或者notify_all()。
notify_all():会唤醒所有等待队列中阻塞的线程,存在锁争用,只有一个线程能够获得锁。其余未获取锁的线程继续尝试获得锁(类似于轮询),而不会再次阻塞。当持有锁的线程释放锁时,这些线程中的一个会获得锁。而其余的会接着尝试获得锁。
————————————————
版权声明:本文为CSDN博主「吃素的施子」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/feikudai8460/article/details/109604690

线程通信与同步

  1. 信号量:https://blog.csdn.net/ljianhui/article/details/10813469
  2. 互斥量:见线程锁部分
  3. 条件变量:condition_variable
    [c++11]多线程编程(六)——条件变量(Condition Variable)

摘抄6
互斥量可以保护共享数据的修改,如果线程正在等待共享数据的某个条件出现,仅用互斥量的话就需要反复对互斥对象锁定解锁,以检查值的变化,这样将频繁查询的效率非常低。
条件变量可以让等待共享数据条件的线程进入休眠,并在条件达成时唤醒等待线程,提供一种更高效的线程同步方式。条件变量一般和互斥锁同时使用,提供一种更高效的线程同步方式。
————————————————
版权声明:本文为CSDN博主「低头看天,抬头走路」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/rusbme/article/details/97620877

  1. 读写锁:shared_lock
    C++实现读写锁ReadWriteLock
    C++11读写锁的实现 是上一篇的修改版
    C++多线程-读写锁 看文章总结部分

摘抄7
在编写多线程的时候,有一种情况是十分常见的。那就是,有些公共数据修改的机会比较少。相比较改写,它们读的机会反而高的多。通常而言,在读的过程中,往往伴随着查找的操作,中间耗时很长。给这种代码段加锁,会极大地降低我们程序的效率。读写锁可以专门处理这种多读少写的情况。
————————————————
版权声明:本文为CSDN博主「cwl_java」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42528266/article/details/103913191

线程安全

摘抄8
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

线程与进程

  1. 进程是系统进行任务调度和资源分配的最小单位,进程之间可以并发执行。
  2. 线程是程序执行流的最小单元,一个进程可以有多个线程,进程内的线程在其他进程不可见。
  3. 线程切换快于进程切换。
  4. 任务调度:时间片轮转,每个任务执行一个时间片的时间长度,时间片结束后,强制暂停,执行另一个时间片的程序,等到该任务的时间片再次到来。
进程间的通信方式
  1. 匿名管道:https://blog.csdn.net/ljianhui/article/details/10168031
    半双工,父子进程
//创建
#include <unistd.h>
int pipe (int fd[2]);	//返回:成功返回0,出错返回-1    fd参数返回两个文件描述符,fd[0]指向管道的读端,fd[1]指向管道的写端。
//创建子进程
pid_t id = fork(); 

在这里插入图片描述

  1. 消息队列:https://blog.csdn.net/ljianhui/article/details/10287879
  2. 有名管道:https://blog.csdn.net/ljianhui/article/details/10202699
  3. 信号量:https://blog.csdn.net/ljianhui/article/details/10243617
  4. 信号:https://blog.csdn.net/ljianhui/article/details/10128731
  5. 共享内存:https://blog.csdn.net/ljianhui/article/details/10253345
  6. 数据报套接字:https://blog.csdn.net/ljianhui/article/details/10697935
  7. 数据流套接字:https://blog.csdn.net/ljianhui/article/details/10477427

其他摘抄和参考

摘抄1
从C++11开始,标准库里已经包含了对线程的支持,std::thread是C++11标准库中的多线程的支持库,pthread.h是标准库没有添加多线程之前的在Linux上用的多线程库,而之前在windows上的多线程支持要包含wndows.h

  1. [c++11]多线程编程(一)——初识
  2. [c++11]多线程编程(二)——理解线程类的构造函数
  3. C++ thread用法总结(整理)
  4. Thread之三:Thread Join()的用法
  5. 基于C++11实现线程池的工作原理
  6. C++11条件变量:notify_one()与notify_all()的区别
  7. c++11 之emplace_back 与 push_back的区别
  8. 进程与线程
  9. 进程间的通信方式——pipe(管道)
  10. Linux进程间通信——使用消息队列
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值