C++多线程学习笔记(一)

今天是五月三号,五一放假五天,博主也就给自己放了三天假,去游山玩水,吃美食。今天是第四天了,也该慢慢找回学习的状态啦。所以今天博主也是改变自己最近懒惰的状态,来开始自己学习多线程的基础知识。多线程这部分内容对于java,c++爱好者应该不陌生,经常听到或看到的吧。建议在学完c++基础语言知识后的同学们,还是值得学一下这部分内容的(其实也不算很多内容)。下面我们正式开始来看看吧

1.理解多线程。

多线程并发指的是在同一个进程中执行多个线程。C++11提供了语言层面上的多线程,包含在头文件中(必须加上的头文件)。它解决了跨平台的问题。C++11 新标准中引入了5个头文件来支持多线程编程,如下图:

C++多线程学习笔记(一)_第1张图片

2.多线程和多进程的区别(这部分内容了解即可):

多线程并发指的是在同一个进程中执行多个线程。而使用多进程并发是将一个应用程序划分为多个独立的进程(每个进程只有一个线程),这些独立的进程间可以互相通信,共同完成任务。总的来说,多进程比多线程的确定更多。

3.thread头文件

(1)创建多线程:
thread myThread ( thread_fun);//函数形式为void thread_fun(),也可以是函数名就可以

myThread.join(); //同一个函数可以代码复用,创建多个线程

另一种形式:

thread myThread ( thread_fun(100));

myThread.join(); //函数形式为void thread_fun(int x) ,同一个函数可以代码复用,创建多个线程

另一种形式:

std::thread (thread_fun,1).detach();//直接创建线程,没有名字,函数形式为void thread_fun(int x)

小练习:

C++多线程学习笔记(一)_第2张图片

C++多线程学习笔记(一)_第3张图片执行时,看到in thread 1,2,3......弹出时,你就会能理解多线程的作用啦。

(2).join和detch的作用。

当线程启动后,一定要在和线程相关联的thread销毁前,确定以何种方式等待线程执行结束。比如上例中的join。

detach方式,启动的线程自主在后台运行,当前的代码继续往下执行,不等待新线程结束。
join方式,等待启动的线程完成,才会继续往下执行。
可以使用joinable判断是join模式还是detach模式。例如:if (myThread.joinable())   foo.join();

(1)join后面的代码不会被执行,除非子线程结束。特别是当子线程是死循环时,子线程不会结束,也就不会执行join后面的代码。first.join();

 (2)主线程不会等待子线程结束。如果主线程运行结束,程序则结束。特别是当子线程是死循环时,子线程不会结束,而用detach可以结束子线程的死循环,执行后面的代码。first.detach();总的来说,就是主线程与子线程分离,守护线程。这有一个坑就是主线程退出后,有可能出现子线程还没有退出的情况。

因此在实际的开发中,我们多用优化完的join来代替detach。那么怎么优化呢?如图:

C++多线程学习笔记(一)_第4张图片多加了两步操作。再在主函数中加几步即可,如图

C++多线程学习笔记(一)_第5张图片

这里还有一个就是创建一个thread对象,如thread th;th=thread(子线程函数名,数字,变量,字符串,类对象) 也就是说可以有五个参数哦

另外,子线程也是可以传指针参数的哦,

C++多线程学习笔记(一)_第6张图片

也可以用引用传入参数哦,子线程要是用引用的话,如下图: 

C++多线程学习笔记(一)_第7张图片

 主函数中需要用ref来声明引用哦,不然编译器会以为是普通变量。如下图的ref(p)。拓展一下,其实模板函数中引用都是要用到特殊声明的

 C++多线程学习笔记(一)_第8张图片

(3)this_thread

this_thread是一个类,它有4个功能函数,具体如下:

C++多线程学习笔记(一)_第9张图片

4.mutex头文件

mutex头文件主要声明了与互斥量(mutex)相关的类。mutex提供了4种互斥类型,如下表所示。

C++多线程学习笔记(一)_第10张图片

std::mutex 是C++11 中最基本的互斥量,std::mutex 对象提供了独占所有权的特性——即不支持递归地对 std::mutex 对象上锁,而 std::recursive_lock 则可以递归地对互斥量对象上锁。

(1)lock与unlock

  • lock():资源上锁
  • unlock():解锁资源
  • trylock():查看是否上锁,它有下列3种类情况:

(1)未上锁返回false,并锁住;
(2)其他线程已经上锁,返回true;
(3)同一个线程已经对它上锁,将会产生死锁。

 死锁:是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

同一个mutex变量上锁之后,一个时间段内,只允许一个线程访问它。

例子:大家如果有去上机实践,会发现不会像下面一样出现交替打印现象。

C++多线程学习笔记(一)_第11张图片

如果是不同mutex变量,因为不涉及到同一资源的竞争,所以下列代码运行可能会出现交替打印的情况,或者另一个线程可以修改共同的全局变量!!!例子如下:如果大家有去上机实践一下,会发现出现交替打印的现象

C++多线程学习笔记(一)_第12张图片

 (2)lock_guard

创建lock_guard对象时,它将尝试获取提供给它的互斥锁的所有权。当控制流离开lock_guard对象的作用域时,lock_guard析构并释放互斥量。

lock_guard的特点:

创建即加锁,作用域结束自动析构并解锁,无需手工解锁
不能中途解锁,必须等作用域结束才解锁
不能复制
例子如下:

C++多线程学习笔记(一)_第13张图片

(3)unique_lock

简单地讲,unique_lock 是 lock_guard 的升级加强版,它具有 lock_guard 的所有功能,同时又具有其他很多方法,使用起来更强灵活方便,能够应对更复杂的锁定需要。

特点:

创建时可以不锁定(通过指定第二个参数为std::defer_lock),而在需要时再锁定
可以随时加锁解锁
作用域规则同 lock_guard,析构时自动释放锁
不可复制,可移动
条件变量需要该类型的锁作为参数(此时必须使用unique_lock)
所有 lock_guard 能够做到的事情,都可以使用 unique_lock 做到,反之则不然。那么何时使lock_guard呢?很简单,需要使用锁的时候,首先考虑使用 lock_guard,因为lock_guard是最简单的锁。

例子如下:

C++多线程学习笔记(一)_第14张图片
 

 最后扩展一下:这里有一个不常见的语法

C++多线程学习笔记(一)_第15张图片

 这里是将num的值赋予num_things,多用小括号,这里用中括号也不是不可以。这语法以后见到就不会陌生啦。

好啦,关于c++多线程前两个头文件的分享就到这啦,

本贴为博主亲手整理。如有错误,请评论区指出,一起进步。谢谢大家的浏览.

你可能感兴趣的:(C++,学习,c++)