C++ 多线程之初识多线程

写在前面:

        是假老练与C扎扎还是假老练与风车车呢, 但是这个好像貌似不太重要, 重要的是下面的正文, 嘻嘻~~~

 

目录

1. 什么是进程

1.1 操作系统资源调度的基本单位

1.2 进程的特性:

2. 什么是线程

2.1 操作系统调度的基本单位

3. 什么是并发

3.1 并发

3.2 并发的实现

3.2.1 多个进程实现并发

3.2.2 单进程,多个线程实现并发

4. C++线程的创建

4.1 使用的头文件

4.2 主线程先于子线程结束造成的问题

4.3 join的使用

4.4 detach的使用

4.5 joinable的使用 

5. 多线程的创建

5.1 普通函数创建线程

5.2 Lambda创建线程

5.3 带参函数创建线程

5.3.1 普通类型参数

5.3.2 结构体类型参数

5.3.3 引用参数

5.3.4 智能指针作为参数传递

5.4 类的成员函数创建线程

5.4.1 仿函数形式

5.4.2 普通成员函数方式

6. 与进程相比,线程的优点


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. 与进程相比,线程的优点

  1. 线程启动速度更快,更轻量级
  2. 系统资源开销更少,执行速度更快,比如共享内存这种通信方式比任何其他的通信方式都快
  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

石小浪♪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值