九、多线程
9. 多线程其他相关知识
线程安全
多个线程并发同一段代码时,不会出现不同的结果,则说明这段代码是线程安全的。常见对全局变量或者静态变量进行操作,并且没有锁保护的情况下,就可能会出现线程安全的问题。我们之前学过可重入,同一个函数被不同的执行流调用,当前一个流程还没有执行完,就有其他的执行流再次进入,我们称之为重入。一个函数在重入的情况下,运行结果不会出现任何不同或者任何问题,则该函数被称为可重入函数,否则,是不可重入函数。
函数是可重入的,那就是线程安全的。
函数是不可重入的,那就不能由多个线程使用,有可能引发线程安全问题
如果一个函数中有全局变量,那么这个函数既不是线程安全也不是可重入的。
可重入函数是线程安全函数的一种。
线程安全不一定是可重入的,而可重入函数则一定是线程安全的。
如果将对临界资源的访问加上锁,则这个函数是线程安全的,但如果这个重入函数若锁还未释放则会产生死锁,因此是不可重入的。
死锁
死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所站用不会释放的资源而处于的一种永久等待状态。
如:线程A持有a资源,想申请b资源,线程B持有b资源,想申请a资源。线程AB都想要对方的资源,但是不释放自己的资源,就会产生死锁。
死锁的四个必要条件
①互斥条件:一个资源每次只能被一个执行流使用。
②请求与保持条件:一个执行流因请求资源而阻塞时,对已获得的资源保持不放。
③不剥夺条件:一个执行流已获得的资源,在末使用完之前,不能强行剥夺。
④循环等待条件:若干执行流之间形成一种头尾相接的循环等待资源的关系。
避免死锁的方法
①破坏死锁的四个必要条件。②加锁顺序一致。③避免锁未释放的场景。④资源一次性分配。
线程安全的单例模式
单例模式是一种创建型 设计模式,它保证一个类只能创建一个实例,并提供一个全局访问点。在单例模式中,类的构造函数被声明为私有的,这样外部无法直接实例化该类。而是提供一个静态方法或者属性来获取该类的实例,该方法或属性负责创建实例并返回,确保了只有一个实例被创建。同时,该实例会被保存在私有的静态变量中,以便全局访问。
饿汉单例模式和懒汉单例实现模式
饿汉式单例模式是一种 在类加载时就创建实例 的实现方式,无论是否使用该实例,都会在类加载阶段就创建出来。
class Singleton {
private:
// 私有静态成员变量,存储唯一实例
static Singleton* instance;
// 私有构造函数,防止外部实例化
Singleton() {}
public:
// 公有静态成员函数,返回实例
static Singleton* getInstance() {
return instance;
}
};
// 在类外部初始化静态成员变量
Singleton* Singleton::instance = new Singleton();
饿汉单例模式的优点:
①简单直观,线程安全。
②在类加载时就创建实例,避免了多线程并发访问的问题。
与饿汉单例模式不同,懒汉单例模式是指 在需要的时候才创建实例 的单例模式。
class Singleton {
private:
// 私有静态成员变量,存储唯一实例
static Singleton* instance;
// 私有构造函数,防止外部实例化
Singleton() {}
public:
// 公有静态成员函数,返回实例
static Singleton* getInstance() {
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
};
// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;
懒汉单例模式的优点:在需要的时候才进行初始化,避免了资源的浪费。
懒汉单例模式的缺点:多线程环境下可能存在线程安全的问题,可能会同时创建多个实例。
线程安全版的懒汉单例模式:
#include <mutex>
class Singleton {
private:
static Singleton* instance;
static std::mutex mutex;
Singleton() {}
public:
static Singleton* getInstance() {
if (instance == nullptr) {
// 创建时加锁
std::lock_guard<std::mutex> lock(mutex);
if (instance == nullptr) {
instance = new Singleton();
}
}
return instance;
}
};
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex;