参考博客:https://blog.csdn.net/qq_38231713/category_10001159.html
一、单例设计模式下多线的内存共享
1、单例设计模式
????????在整个项目中某些类只允许存在一个对象,这种类被称为单例类
? ? ? ? 类的构造函数是私有的,通过静态成员函数进行实例化
2、单例设计模式中的共享数据
在多个线程中都需要使用这个对象,都需要进行构造,但是只有在这个对象为NULL的时候才能进行构造,所以需要使用lock_guard进行保护,而为了提高效率,使用了双重锁定的判断方式
#include <iostream>
#include <mutex>
using namespace std;
mutex myMutex;
//懒汉模式
class Singleton
{
public:
static Singleton * getInstance() {
//双重锁定 提高效率
if (instance == NULL) {
lock_guard<mutex> myLockGua(myMutex);
if (instance == NULL) {
instance = new Singleton;
}
}
return instance;
}
private:
Singleton() {}
static Singleton *instance;
};
Singleton * Singleton::instance = NULL;
//饿汉模式
class Singleton2 {
public:
static Singleton2* getInstance() {
return instance;
}
private:
Singleton2() {}
static Singleton2 * instance;
};
Singleton2 * Singleton2::instance = new Singleton2;
int main(void)
{
Singleton * singer = Singleton::getInstance();
Singleton * singer2 = Singleton::getInstance();
if (singer == singer2)
cout << "二者是同一个实例" << endl;
else
cout << "二者不是同一个实例" << endl;
cout << "---------- 以下 是 饿汉式 ------------" << endl;
Singleton2 * singer3 = Singleton2::getInstance();
Singleton2 * singer4 = Singleton2::getInstance();
if (singer3 == singer4)
cout << "二者是同一个实例" << endl;
else
cout << "二者不是同一个实例" << endl;
return 0;
}
? ? ? ? 单例对象的创建是通过指针,但是指针没办法自动析构,所以使用了一种类中类的方式进行自动析构,在实例化函数中添加一个类中类的静态变量,在类中类的析构函数中析构单例类对象,因为静态变量的生命周期持续到程序结束,所以在程序结束的时候会自动析构单例对象
class Singelton
{
public:
static Singleton * getInstance() {
if (instance == NULL) {
static CGarhuishou huishou;
instance = new Singelton;
}
return instance;
}
class CGarhuishou {
public:
~CGarhuishou()
{
if (Singleton::instance)
{
delete Singleton::instance;
Singleton::instance = NULL;
}
}
};
private:
Singleton() {}
static Singleton *instance;
};
Singleton * Singleton::instance = NULL;
3、std::call_once()函数模板
? ? ? ? 第一个参数是标记std::once_flag,第二个参数是函数名,该函数只被调用一次
? ? ? ? 这个类模板具有互斥量的功能
once_flag g_flag;
class Singleton
{
public:
static void CreateInstance()//call_once保证其只被调用一次
{
instance = new Singleton;
}
//两个线程同时执行到这里,其中一个线程要等另外一个线程执行完毕
static Singleton * getInstance() {
call_once(g_flag, CreateInstance);
return instance;
}
private:
Singleton() {}
static Singleton *instance;
};
Singleton * Singleton::instance = NULL;
二、条件变量std::condition_variable
? ? ? ? 配合unique_lock使用,当满足某些条件时做出反应
std::mutex mymutex1;
std::unique_lock<std::mutex> sbguard1(mymutex1);
std::condition_variable condition;
condition.wait(sbguard1, [this] {if (!msgRecvQueue.empty())
return true;
return false;
});
condition.wait(sbguard1);
1、wait()与notify_one()
? ? ? ? wait()第二个参数默认false
? ? ? ? wait()第二个参数为false时,解锁互斥量(之前在unique_lock中已经上锁),并阻塞到本行,直到另一个线程中调用了notify_one(),此时wait()被重新唤醒,然后重新判断第二个参数
? ? ? ? wait()第二个参数为true时,继续向下执行
? ? ? ? 如果有多个线程进入wait,notify_one一次会随机唤醒其中某一个线程,如果需要唤醒所有线程则需要使用notify_all()
#include <thread>
#include <iostream>
#include <list>
#include <mutex>
using namespace std;
class A {
public:
void inMsgRecvQueue() {
for (int i = 0; i < 100000; ++i)
{
cout << "inMsgRecvQueue插入一个元素" << i << endl;
std::unique_lock<std::mutex> sbguard1(mymutex1);
msgRecvQueue.push_back(i);
//尝试把wait()线程唤醒,执行完这行,
//那么outMsgRecvQueue()里的wait就会被唤醒
//只有当另外一个线程正在执行wait()时notify_one()才会起效,否则没有作用
condition.notify_one();
}
}
void outMsgRecvQueue() {
int command = 0;
while (true) {
std::unique_lock<std::mutex> sbguard2(mymutex1);
// wait()用来等一个东西
// 如果第二个参数的lambda表达式返回值是false,那么wait()将解锁互斥量,并阻塞到本行
// 阻塞到什么时候为止呢?阻塞到其他某个线程调用notify_one()成员函数为止;
//当 wait() 被 notify_one() 激活时,会先执行它的 条件判断表达式 是否为 true,
//如果为true才会继续往下执行
condition.wait(sbguard2, [this] {
if (!msgRecvQueue.empty())
return true;
return false;});
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
//因为unique_lock的灵活性,我们可以随时unlock,以免锁住太长时间
sbguard2.unlock();
cout << "outMsgRecvQueue()执行,取出第一个元素" << endl;
}
}
private:
std::list<int> msgRecvQueue;
std::mutex mymutex1;
std::condition_variable condition;
};
int main() {
A myobja;
std::thread myoutobj(&A::outMsgRecvQueue, &myobja);
std::thread myinobj(&A::inMsgRecvQueue, &myobja);
myinobj.join();
myoutobj.join();
}
? ? ? ? 以上代码中inMsgRecvQueue和outMsgRecvQueue并不是对称执行的
三、async、future、packaged_task、promise
? ? ? ? 需包含新的头文件
#include <future>
1、std::async和std::future创建后台任务并获得返回值
? ? ? ? std::async是一个类模板,用来创建一个异步任务,异步任务的创建方式和线程的创建方式相同
? ? ? ? std::future是一个对象,用来获取线程运行结束后的返回值
? ? ? ? std::future对象有wait()函数,用于等待线程执行结束,效果和join()很像
? ? ? ? std::future对象通过get()函数来获取线程返回值,只能使用一次get,移动语义
#include <iostream>
#include <future>
using namespace std;
class A {
public:
int mythread(int mypar) {
cout << mypar << endl;
return mypar;
}
};
int mythread() {
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
return 5;
}
int main() {
A a;
int tmp = 12;
cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
std::future<int> result1 = std::async(mythread);
cout << "continue........" << endl;
cout << result1.get() << endl; //卡在这里等待mythread()执行完毕,拿到结果
//类成员函数
std::future<int> result2 = std::async(&A::mythread, &a, tmp); //第二个参数是对象引用才能保证线程里执行的是同一个对象
cout << result2.get() << endl;
//或者result2.wait();
cout << "good luck" << endl;
return 0;
}
? ? ? ?std::future的成员函数std::future_status status = result.wait_for(std::chrono::seconds(几秒));?等待一段时间去判断当前异步任务的状态,std::future_status是枚举类型,有三种状态
????????????????std::future_status::timeout? ?线程还在执行
????????????????std::future_status::ready? 线程执行结束
????????????????std::future_status::deferred? 线程还没开始执行
#include <iostream>
#include <future>
using namespace std;
int mythread() {
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
return 5;
}
int main() {
cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
std::future<int> result = std::async(mythread);
cout << "continue........" << endl;
//cout << result1.get() << endl; //卡在这里等待mythread()执行完毕,拿到结果
//等待1秒
std::future_status status = result.wait_for(std::chrono::seconds(1));
if (status == std::future_status::timeout) {
//超时:表示线程还没有执行完
cout << "超时了,线程还没有执行完" << endl;
}
//类成员函数
return 0;
}
????????std::async的启动方式std::lunch::deferred表示线程的入口函数延迟执行,直到wait()或者get()开始执行,如果没有wait和get则直接不执行;此方式创建了异步任务但是并没有创建新线程
#include <iostream>
#include <future>
using namespace std;
int mythread() {
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
return 5;
}
int main() {
cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
std::future<int> result1 = std::async(std::launch::deferred ,mythread);
cout << "continue........" << endl;
cout << result1.get() << endl; //卡在这里等待mythread()执行完毕,拿到结果
cout << "good luck" << endl;
return 0;
}
????????std::async的启动方式std::lunch::async,在创建异步任务的时候会创建新线程
???????? std::async的启动方式缺省时其参数为std::lunch::async |?std::lunch::deferred? ;并不能确定是立即执行还是延时执行,系统根据当前资源自行决定;可以使用std::future_status进行判断
2、std::packaged_task 打包任务
? ? ? ? 将各种可调用对象封装起来,方便作为线程的入口函数来调用,以及后续获取线程返回值
#include <thread>
#include <iostream>
#include <future>
using namespace std;
int mythread(int mypar) {
cout << mypar << endl;
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
return 5;
}
int main() {
cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
//我们把函数mythread通过packaged_task包装起来
//参数是一个int,返回值类型是int
std::packaged_task<int(int)> mypt(mythread);
std::thread t1(std::ref(mypt), 1);
t1.join();
std::future<int> result = mypt.get_future();
//std::future对象里包含有线程入口函数的返回结果,这里result保存mythread返回的结果。
cout << result.get() << endl;
return 0;
}
? ? ? ? 封装后的对象可以调用get_future()成员函数来得到一个future对象,再使用future的get()函数获取线程的返回值
3、std::promise类模板
? ? ? ? 可以在线程通过set_value()成员函数进行赋值,然后在其他线程中将其取出来
#include <thread>
#include <iostream>
#include <future>
using namespace std;
void mythread(std::promise<int> &tmp, int clac) {
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
int result = clac;
tmp.set_value(result); //结果保存到了tmp这个对象中
return;
}
vector<std::packaged_task<int(int)>> task_vec;
int main() {
std::promise<int> myprom;
std::thread t1(mythread, std::ref(myprom), 180);
t1.join(); //在这里线程已经执行完了
std::future<int> fu1 = myprom.get_future(); //promise和future绑定,用于获取线程返回值
auto result = fu1.get();
cout << "result = " << result << endl;
}
四、std::shared_future类模板
???????std::shared_future,其get()成员函数复制数据,复制语义
? ? ? ?std::future,其get()成员函数移动数据,移动语义
? ? ? ? future对象的share()函数可以获得shared_future对象,shared_future对象可使用get_future()函数进一步进行复制
#include <thread>
#include <iostream>
#include <future>
using namespace std;
int mythread() {
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
return 5;
}
int main() {
cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
std::packaged_task<int()> mypt(mythread);
std::thread t1(std::ref(mypt));
std::future<int> result = mypt.get_future();
bool ifcanget = result.valid(); //判断future中的值是不是一个有效值
std::shared_future<int> result_s(result.share()); //执行完毕后result_s里有值,而result里空了
//std::shared_future<int> result_s(std::move(result));
//通过get_future返回值直接构造一个shared_future对象
//std::shared_future<int> result_s(mypt.get_future());
t1.join();
auto myresult1 = result_s.get();
auto myresult2 = result_s.get();
cout << "good luck" << endl;
return 0;
}
五、std::atomic原子操作
原子锁用于对一个简单变量的读写操作的保护,效率比mutex高
需要包含头文件
#include <atomic>
#include <iostream>
#include <thread>
#include <atomic>
using namespace std;
std::atomic<int> g_count = 0; //封装了一个类型为int的 对象(值)
void mythread1() {
for (int i = 0; i < 1000000; i++) {
g_count++;
}
}
int main() {
std::thread t1(mythread1);
std::thread t2(mythread1);
t1.join();
t2.join();
cout << "正常情况下结果应该是200 0000次,实际是" << g_count << endl;
}
????????原子锁适用于** -- += -=等运算符
? ? ? ? 原子变量a执行 a = a + 1;会出错
|