本篇介绍新的篇章,主要介绍线程与同步的知识。
早期C++是没有考虑多线程的,随着语言的发展,C++中增加了线程与同步的相关标准库。
总结: C++中对线程进行了封装创建新的线程,使用回调函数作为新的线程下的起点。
C++新特性27_线程thread的使用
1. C++11为多线程进行的标准库扩充
为了实现在不同系统下的多线程及同步功能,C++标准库进行了如下的扩充:这是一种语言级别的线程支持
- std::thread
- std::mutex/std::unique_lock
- std::future/std::packaged_task
- std::condition_variable
2. 线程的概念及应用
线程:进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。
(1)线程内核对象。操作系统用它来管理线程,存放线程统计信息。
(2)线程堆栈,用于维护线程在执行代码时,需要的所有函数参数和局部变量。
下图做了解

通俗点:
举个例子:人在吃饭的时候可能心不在焉,同时玩手机、聊天或者与好几个人聊天,这个过程我们感觉同时做了好几件事
计算机也是类似的,可以一边玩游戏,一边听音乐,但是早期的CPU是单核的(某一瞬间只能执行某一条指令),按道理不可以同时支持做好几件事,但是实际上是可以实现的,那如何实现的呢?那是因为我们把CPU划分为很多的“时间片”
什么是时间片呢?
时间片:某一间A教室(1班,2班),那如何实现一天让1班,2班都在A教室上班?
方法: 把时间划分,划分成上午(1班)和下午(2班)。
那电脑是如何实现的呢?也是类似的:
cpu(听歌代码,游戏代码),把cpu时间划分,划分为片段20ms,由线程1(听歌)和线程2(游戏代码)交替运行。这时候我们就有种错觉,我们同时在听歌和玩游戏。
我们把CPU所占用的时间称之为时间片,听歌和游戏称之为线程1和线程2,这也会带来我们调试时的一些问题,但是优势大于问题。
3.多线程的核心
回调函数:一旦创建一个线程 就会以这个线程的函数作为一个新的起点,即回调函数会在新的线程中与主线程一起开始运行,这个时候我们程序就会有2个线程 主线程和子线程
4. windows下经典的线程写法
(1)利用windows下的API进行多线程的经典实现方法如下:
#include <iostream>
#include <windows.h>
#include <tchar.h>
using namespace std;
//子线程的回调函数
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
std::cout << "hello world" << std::endl;
return 1;
}
int _tmain(int argc, _TCHAR* argv[])
{
//使用的是windows下的API
DWORD dwThreadID = 0;
//创建一个子线程
HANDLE hThread = CreateThread(
NULL,
0,//默认栈大小
//线程的回调函数 一旦创建一个线程 就会以这个线程的函数作为一个新的起点
//这个时候我们程序就会同时有2个线程 主线程和子线程,看起来是同时运行
ThreadProc,//线程回调函数 函数指针
NULL,//参数
0,//或者CREATE_SUSPENDED 表示是否暂停
&dwThreadID //线程
);
//等待某一个信号量被触发
//主线程运行完后会退出 但是子线程可能没有运行完 主线程会使用下边的函数等待子线程一起退出
//INFINITE代表等待无限时间
WaitForSingleObject(hThread, INFINITE);
return 0;
}
(2)设置断点如下:

主线程按步运行至WaitForSingleObject(hThread, INFINITE)卡死等待子线程运行完成;
ThreadProc之后,程序会自动跳转至子线程的回调函数中,主线程等待子线程运行完一起退出
(3)查看2个线程当前运行位置
主线程运行位置,卡死等待子线程运行完成

子线程运行位置

F5之后,程序运行到最后return 0;位置,然后主线程和子线程一起退出

但是这样做很麻烦,不同的系统对于多线程的写法都不一样,上面的代码在linux系统下又是一种新的形式,我们需要在语言上进行统一,在语言层次提供了封装。
5. C++11对线程的封装
C++11中提供了封装,其经典写法如下:
#include <tchar.h>
#include <iostream>
#include <thread>
using namespace std;
void foo() {
std::cout << "hello world" << std::endl;
}
//c++11 标准写法
int _tmain(int argc, _TCHAR* argv[])
{
//创建了线程对象 核心的回调函数 这里回调函数为foo()
std::thread t(foo);
//主线程在等待子线程的结束
t.join();
return 0;
}

运行跳转至子线程的回调函数

另外一种写法,将回调函数写为Lambda表达式(匿名函数):
int _tmain(int argc, _TCHAR* argv[])
{
//创建了线程对象 核心的回调函数 这里回调函数为foo()
std::thread t([] {
std::cout << "hello world" << std::endl;
});
//主线程在等待子线程的结束
t.join();
return 0;
}
6.学习视频地址:C++新特性27_线程thread的使用
本文介绍了C++11中新增的线程与同步标准库,涵盖了线程概念、多线程核心、Windows下的线程写法以及C++11对线程的封装等内容。
9324

被折叠的 条评论
为什么被折叠?



