今天学进程
进程的状态
(本科的考点我记得哈哈)
什么是线程
线程的状态
线程和进程的区别
一个共享 一个私有 独立
多线程的优缺点
线程的分类
内核支持线程
用户级线程
组合方式线程
协程coroutine
进程 分配资源的最小单位
线程 是cpu调度的最小单位
C++线程API的使用
初始化构造函数 传入可运行的函数对象
代码环节
创建线程
1.全局函数
给一个任务去跑
2.成员函数
如何把this指针穿进去
获取函数指针
匿名函数lambda
capture 捕获函数以外那些变量
=按值捕获 保证外面的变量是对的
&按引用来捕获
重载()的操作符
第二个()是函数的参数
join
不想等detach
不阻塞,不同步
#include <iostream>
#include <thread>
using namespace std;int gValue = 0;static void work_thread(int a){gValue += a;cout << "work thread"<< endl;cout << "gval= "<< gValue<<endl;
}class MyClass {
public:// 成员函数void memberFunction() {std::cout << "Thread started with member function" << std::endl;}
};int main() {auto t = thread(work_thread, 1);t.join();// // 使用全局函数启动线程// std::thread t1(globalFunction);// 使用成员函数启动线程MyClass obj;std::thread t2(&MyClass::memberFunction, &obj);t2.join();// 使用 Lambda 函数启动线程auto lambdaFunction = []() {std::cout << "Thread started with lambda function" << std::endl;};std::thread t3(lambdaFunction);t3.join();// // 等待所有线程结束// t1.join();// t2.join();// t3.join();return 0;
}
亲测比较好玩,今天老师带着写啊啊啊啊啊
auto关键字是干嘛的
auto
关键字是 C++11 引入的一项功能,用于自动类型推导。它可以在变量声明时根据初始化表达式的类型自动推导出变量的类型,从而减少代码中的冗长和提高可读性。以下是一些使用 auto
的示例及其详细解释。
#include <iostream>
#include <vector>int main() {// 自动推导为 int 类型auto x = 5; std::cout << "x = " << x << ", type: int" << std::endl;// 自动推导为 double 类型auto y = 3.14;std::cout << "y = " << y << ", type: double" << std::endl;// 自动推导为 const char* 类型auto str = "Hello, World!";std::cout << "str = " << str << ", type: const char*" << std::endl;// 自动推导为 std::vector<int> 类型std::vector<int> vec = {1, 2, 3, 4, 5};auto iter = vec.begin(); std::cout << "First element of vec: " << *iter << std::endl;return 0;
}
光听了 代码 没跟上。。。
#include<iostream>
#include<thread>
#include<functional>
using namespace std;int func_invoker(std::function<int(int,int)> func_obj){return func_obj(2,3);
}int main(){int c = 1;int retval = func_invoker([=](int a, int b)-> int {return a +b + c;});cout<< "retval: "<< retval<<endl;return 0;}
为什么要线程池
线程池是一种用于管理一组工作线程的设计模式,它能够有效地控制并发线程的数量,减少线程创建和销毁的开销,并优化资源利用。线程池在不同的实现中可以有各种状态,但通常,线程池的工作状态包括以下四种:创建、运行、等待、销毁。
### 1. 创建状态(Creating/Initializing)
在创建状态下,线程池正在初始化和分配资源。这个过程包括以下几个步骤:
- **分配线程池对象**:创建一个线程池实例。
- **设置参数**:配置线程池的参数,如核心线程数、最大线程数、空闲线程的存活时间、任务队列等。
- **启动核心线程**:如果线程池设置了核心线程数,则会创建并启动这些核心线程,使其处于等待任务的状态。
创建状态的目的是为线程池准备必要的资源和线程,以便线程池能够有效地执行任务。
### 2. 运行状态(Running)
在运行状态下,线程池可以接收和执行任务。此状态是线程池的主要工作状态,涉及以下活动:
- **接受任务**:通过 `submit` 或 `execute` 方法将任务提交到线程池。
- **任务调度**:线程池从任务队列中取出任务,并分配给空闲的工作线程执行。
- **任务执行**:工作线程执行任务,并在完成后返回线程池以待接收新的任务。
在运行状态下,线程池可以动态调整线程数量,启动新线程处理任务,或者在任务少时减少线程数。
### 3. 等待状态(Waiting/Idle)
线程池的等待状态是指线程池中的所有工作线程都处于空闲状态,等待新任务到达。这种状态通常出现在以下情况下:
- **任务完成**:所有提交的任务已经执行完毕,线程池中的工作线程没有任务可执行。
- **等待新任务**:工作线程在任务队列中等待新任务的到来。
在等待状态下,线程池可以根据配置选择是保持一定数量的空闲线程,还是逐渐销毁空闲线程以节省资源。
### 4. 销毁状态(Shutting Down/Terminated)
在销毁状态下,线程池正在关闭并释放资源。此状态包括以下几个步骤:
- **拒绝新任务**:线程池不再接受新的任务提交。
- **完成已提交任务**:线程池会尽量完成已经提交但未完成的任务。
- **终止工作线程**:逐步关闭和销毁所有工作线程,确保所有线程安全退出。
- **释放资源**:清理和释放线程池占用的各种资源,如任务队列、锁、内存等。
销毁状态可以通过两种方式触发:
- **正常关闭**:调用 `shutdown` 方法,线程池不再接收新任务,但会执行完队列中的所有任务后再关闭。
- **强制关闭**:调用 `shutdownNow` 方法,线程池立即停止执行当前任务,并中断所有工作线程。
### 总结
线程池的四种主要工作状态为:创建、运行、等待、销毁。这些状态分别对应线程池的不同生命周期阶段,从初始化到执行任务,再到等待新任务,最后到安全关闭和释放资源。理解这些状态及其转换对于设计和使用线程池以提高并发性能和资源利用率至关重要。
线程同步和互斥
什么是竞争
内存资源的竞争
++
- -
什么是死锁
定义获取死锁顺序
哲学家银行家吃饭
互斥和同步
条件变量
wait会把锁释放掉
异步编程future
线程安全 并发编程
数据结构设计
分段加锁 提高并发 程序不变复杂
前端的数据结构类型多
原子变量(atomic variables)是多线程编程中的一种特殊类型的变量,具备原子性操作的特性。在并发编程中,多个线程可能同时访问和修改共享的数据,
而原子变量能够保证对其操作的原子性,即不会被中断或者同时被其他线程修改。
原子操作是不可分割的单元,要么执行完全,要么不执行,不会被线程调度机制打断。
特性和用途
-
原子性操作:原子变量支持的操作是原子的,不会被中断,也不会被其他线程同时修改。这包括赋值、加载、存储、比较和交换等操作。
-
避免竞态条件:使用原子变量可以避免由于多个线程并发访问共享数据而导致的竞态条件(race condition)问题。
-
线程安全:原子变量操作保证线程安全,不需要额外的锁来保护其操作。
-
性能优化:与使用互斥锁相比,原子变量操作通常具有更好的性能,因为它们不涉及线程的上下文切换或内核态和用户态之间的切换。
C++ 中的原子变量
在 C++11 标准中,引入了 <atomic>
头文件来支持原子操作。主要的原子变量类型包括:
-
std::atomic<T>
:模板类,支持模板类型T
的原子操作。例如,std::atomic<int>
、std::atomic<bool>
等。 -
原子操作函数:例如
std::atomic_load
、std::atomic_store
、std::atomic_exchange
、std::atomic_compare_exchange_weak
等,用于加载、存储、交换、比较和交换等操作。
无锁编程
无锁编程是一种在多线程环境中,不使用锁机制(如互斥锁、读写锁等)来保护共享资源的一种编程技术。无锁编程的核心思想是通过硬件提供的原子操作来实现线程安全,以避免锁带来的性能开销和潜在的死锁问题。无锁编程主要依赖于以下技术:
原子操作
原子操作是无锁编程的基础,它确保对变量的操作是不可分割的,不会被线程调度机制打断。常见的原子操作包括:
-
比较并交换(Compare-and-Swap, CAS):这是最常用的原子操作之一,用于比较变量的当前值与预期值,如果相等则更新变量为新值。CAS 操作常用于实现无锁的数据结构和算法。
-
获取并增加(Fetch-and-Add):对变量进行加操作并返回旧值。这对于计数器等简单的无锁数据结构非常有用。
C++ 中的无锁编程
C++11 引入了 <atomic>
头文件,其中包含了一系列原子类型和操作,支持无锁编程。以下是一些常见的原子类型和操作:
std::atomic<T>
:模板类,用于定义原子类型。std::atomic_flag
:最简单的原子类型,用于实现低级别的锁和标志。- 原子操作函数,如
std::atomic_load
、std::atomic_store
、std::atomic_exchange
、std::atomic_compare_exchange_weak
等。
完全没有 并发 不存在共享
threadLocal
作业一:哲学家吃饭
作业2线程池 能提交任务
互斥锁代码代练我没什么机会了,哎,我去开组会了
std::lock_guard<std::mutex> lock(mtx);
:std::lock_guard
是一种 RAII 风格的锁管理器,它在构造时自动锁住给定的互斥锁,在作用域结束时自动解锁。这样可以确保互斥锁在任何情况下(包括异常)都能正确解锁。++counter;
:在锁保护的作用域内安全地修改共享资源counter
。
今天去参加组会了,晚上要学习其他的东西,作业看看明天能不能补吧,不能补就算了,明天写,东东累了,大家要加油呀,今天是第几天了,人少了一些