写在前面:
是假老练与C扎扎还是假老练与风车车呢, 但是这个好像貌似不太重要, 重要的是下面的正文, 嘻嘻~~~
1. 什么是进程
1.1 操作系统资源调度的基本单位
计算机中的程序关于数据集合上的一次运行活动。一个运行中的程序被称为一个进程(必须是运行中的程序)。
1.2 进程的特性:
1. 动态性
进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
2. 并发性
任何进程都可以同其他进程一起并发执行。
3. 独立性
进程是一个能独立运行的基本单位,同时也是操作系统分配资源和调度的独立单位。
4. 结构性
进程由程序、数据和进程控制块三部分组成。
5. 异步性
由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进。
2. 什么是线程
2.1 操作系统调度的基本单位
每个进程都有一个主线程,并且主线程唯一,线程就是一个代码的运行通道。
3. 什么是并发
3.1 并发
一个程序同时执行多个独立的任务,并发的主要目的是提高性能(同时做多个事情)。单核CPU,某一时刻只能执行一个任务, 有操作系统调度,每秒执行多次所谓的“任务切换”,实现并发的假象。而且上下文切换需要时间开销(比如操作系统要保存你切换时的各种状态,变量或状态的存储,执行进度信息,都需要时间开销)。多核CPU,如果任务数小于核数,可以实现真正意义上的并发(硬件并发)
3.2 并发的实现
3.2.1 多个进程实现并发
主要解决进程间通信问题:
同主机,主要使用管道,文件,消息队列,内存共享实现
不同主机,网络编程实现(Socket)
3.2.2 单进程,多个线程实现并发
单个进程中,创建了多个线程,每个线程都有自己独立的运行路径,但是一个进程中所有线程共享地址空间( 一个进程中所有线程共享内存空间),例如:全局变量,全局指针,全局引用都可以在线程之间传递。所以使用多线程开销远远小于多进程。共享内存带来的问题,数据一致性问题(多个线程都要往一块内存空间存储数据,造成资源竞争(可以使用锁解决临界数据脏的问题))。
4. C++线程的创建
4.1 使用的头文件
#include <thread>
4.2 主线程先于子线程结束造成的问题
直接创建线程不做处理会造成**编译器调用abort终止我们的程序**
#include <iostream>
#include <thread>
#include <windows.h>
using namespace std;
void print() {
int count = 2;
int m = 0;
while (count--) {
cout << "主线程执行: m = "<< m++ << endl;
Sleep(1000);
}
}
void printData() {
int n = 0;
while (1) {
cout << "子线程执行: n = "<< n++ << endl;
Sleep(1000);
}
}
int main() {
thread t1(printData); //创建子线程
print(); //主线程执行
return 0;
}
4.3 join的使用
加入/汇合线程,阻塞主线程(主线程等待子线程结束)
#include <iostream>
#include <thread>
#include <windows.h>
using namespace std;
void print() {
int count = 2;
int m = 0;
while (count--) {
cout << "主线程执行: m = "<< m++ << endl;
Sleep(1000);
}
}
void printData() {
int count = 5;
int n = 0;
while (count--) {
cout << "子线程执行: n = "<< n++ << endl;
Sleep(1000);
}
}
int main() {
thread t1(printData);
print();
t1.join();
cout << "主线程结束------" << endl;
return 0;
}
主线程会等待子线程结束
4.4 detach的使用
分离 驻留后台(子线程后台执行)
#include <iostream>
#include <thread>
#include <windows.h>
using namespace std;
void print() {
int count = 2;
int m = 0;
while (count--) {
cout << "主线程执行: m = "<< m++ << endl;
Sleep(1000);
}
}
void printData() {
int count = 5;
int n = 0;
while (count--) {
cout << "子线程执行: n = "<< n++ << endl;
Sleep(1000);
}
}
int main() {
thread t1(printData);
print();
t1.detach();
cout << "主线程结束------" << endl;
return 0;
}
子进程会在后台执行
注: 对于同一个线程,join 和detach只能存在一个
当两者同时存在于同一个线程时:
4.5 joinable的使用
判断当前线程是否可以被join与detach ,如果可以返回true,不可以返回false
#include <iostream>
#include <thread>
#include <windows.h>
using namespace std;
void print() {
int count = 2;
int m = 0;
while (count--) {
cout << "主线程执行: m = "<< m++ << endl;
Sleep(1000);
}
}
void printData() {
int count = 10;
int n = 0;
while (count--) {
cout << "子线程执行: n = "<< n++ << endl;
Sleep(1000);
}
}
int main() {
thread t1(printData);
print();
if (t1.joinable())
cout << "t1可以被join" << endl;
else
cout << "t1不能被join" << endl;
t1.join();
return 0;
}
5. 多线程的创建
5.1 普通函数创建线程
#include <iostream>
#include <thread>
#include <windows.h>
using namespace std;
//普通函数充当线程处理函数创建线程
void print() {
int count = 5;
while (count--) {
cout << "普通函数充当线程处理函数" << endl;
Sleep(1000);
}
}
void test01() {
thread t1(print);
t1.join();
}
int main() {
test01();
return 0;
}
5.2 Lambda创建线程
#include <iostream>
#include <thread>
#include <windows.h>
using namespace std;
//使用Lambda表达式充当线程处理函数
void test02() {
thread t1([]() {
cout << "Lambda表达式充当线程处理函数" << endl;
});
t1.join();
}
int main() {
test02();
return 0;
}
5.3 带参函数创建线程
5.3.1 普通类型参数
#include <iostream>
#include <thread>
#include <windows.h>
using namespace std;
//普通参数
void printData(int num) {
while (num--) {
cout << "num: " << num << endl;
Sleep(1000);
}
}
void test03() {
int num = 5;
thread t1(printData, num);
t1.join();
}
int main() {
test03();
return 0;
}
5.3.2 结构体类型参数
#include <iostream>
#include <thread>
#include <windows.h>
using namespace std;
//结构体参数的传递
struct MM {
string name;
int age;
};
void printMMData(MM mm) {
cout << "name: " << mm.name << "\tage: " << mm.age << endl;
}
void test04() {
MM mm = { "貂蝉",18 };
thread t1(printMMData, mm);
t1.join();
}
int main() {
test04();
return 0;
}
5.3.3 引用参数
#include <iostream>
#include <thread>
#include <windows.h>
using namespace std;
//引用参数
void printReference(int& num) {
num = 5;
while (num--) {
cout << "num: " << num << endl;
Sleep(1000);
}
}
void test05() {
int num = 10;
thread t1(printReference, ref(num)); //包装引用作为传递的值
t1.join();
cout << "主线程 num: " << num << endl;
}
int main() {
test05();
return 0;
}
5.3.4 智能指针作为参数传递
#include <iostream>
#include <thread>
#include <windows.h>
using namespace std;
//智能指针当做函数参数
void printPtr(unique_ptr<int> ptr) {
cout << "智能指针方式: " << ptr.get() << endl;
cout << "智能指针方式: " << *ptr.get() << endl;
}
void test06() {
unique_ptr<int> ptr(new int(10));
cout << "主线程1: ptr: " << ptr.get() << endl;
cout << "主线程1: ptr: " << *ptr.get() << endl;
thread t1(printPtr, move(ptr));
t1.join();
//进行移动之后, 此处地址为0
cout << "主线程2: ptr: " << ptr.get() << endl;
}
int main() {
test06();
return 0;
}
5.4 类的成员函数创建线程
5.4.1 仿函数形式
#include <iostream>
#include <thread>
#include <windows.h>
using namespace std;
//仿函数形式(使用类名的方式调用)
class Stu {
private:
public:
void operator()() {
cout << "重载()的方式实现 " << endl;
}
protected:
};
void test07() {
//有名对象
Stu stu;
thread t1(stu);
t1.join();
//匿名对象
thread t2((Stu()));
t2.join();
}
int main() {
test07();
return 0;
}
5.4.2 普通成员函数方式
#include <iostream>
#include <thread>
#include <windows.h>
using namespace std;
//通过类中的成员函数创建
class MM2 {
public:
void print(int& num) {
num = 5;
while (num--) {
cout << "子线程: num: " << num << endl;
Sleep(1000);
}
}
protected:
private:
};
void test08() {
MM2 mm;
int num = 10;
//指定哪一个类的函数 属于哪一个对象
thread t1(&MM2::print, mm, ref(num)); //不能传入常量,例: ref(10)
t1.join();
}
int main() {
test08();
return 0;
}
6. 与进程相比,线程的优点
- 线程启动速度更快,更轻量级
- 系统资源开销更少,执行速度更快,比如共享内存这种通信方式比任何其他的通信方式都快