如何建CMS网站,设计吧 网站,wordpress里面怎么加链接,用angular做的网站链接目录 线程库基本用法创建线程给线程传递参数线程分离 常见数据未定义错误传递指针或引用指向局部变量的问题传递指针或引用指向已释放的内存的问题类成员函数作为入口函数#xff0c;类对象被提前释放智能指针来解决该问题入口函数为类的私有成员函数 互斥量死锁 lock_guard与… 目录 线程库基本用法创建线程给线程传递参数线程分离 常见数据未定义错误传递指针或引用指向局部变量的问题传递指针或引用指向已释放的内存的问题类成员函数作为入口函数类对象被提前释放智能指针来解决该问题入口函数为类的私有成员函数 互斥量死锁 lock_guard与unique_lockunique_lock std::call_once(单例模式)condition_variable(生产者与消费者模型)C11实现跨平台线程池异步开发futurepackaged_taskpromise 原子操作std::atmoicload()store() 进程是正在运行的程序 线程就是进程中的进程
线程库基本用法
创建线程 但是运行时发现并没有打印helloworld因为主线程运行完了子线程还没有创建好所以需要等待子线程运行完主线程再退出。 join是阻塞的会阻塞主线程的运行
给线程传递参数
直接在thread的函数后面有点像绑定器 线程分离
主线程不用等待子线程结束可以先结束。
常见数据未定义错误
这段会报错 而且也不能传a 因为线程函数传参是值传递即使在函数里面用了引用线程函数拿到的还是复制该引用指向的数据值类型。而且不能把右值传递给左值引用。 所以传递的左右值引用要统一 确实不加引用的话能运行
传递指针或引用指向局部变量的问题
这边int a是不能放在函数里面的因为在函数内部a是局部的当出了test后a就自动销毁了地址也没了所以就引用不到。要把a设为全局变量。 C11的thread默认会复制传递的参数因此直接传递引用会导致引用被复制无法修改原始变量。
传递指针或引用指向已释放的内存的问题
ptr是指向1的一个指针按道理应该是输出1但是输出了0说明这个程序已经是错了 这个错误的原因是在子线程去打印这个1的时候主线程可能已经完成释放指针了那么指针指向的内容会是任何数野指针 改进方法可以主线程加个sleep再释放。 主线程和子线程各跑各的子程序想要访问某个地址某块内存但是主线程已经释放掉了。 那除了sleep还有什么方法
类成员函数作为入口函数类对象被提前释放
和上面一样成员函数在子线程运行想要访问某个资源的时候被主线程释放掉了就取不到资源了 std::thread t(MyClass::func,obj)
智能指针来解决该问题
在解决类的释放问题的时候肯定不能用sleep因为你也不知道程序要跑多少秒我们希望程序能够自动地在调用完类对象之后自动销毁类对象。 那么可以用智能指针来创建对象。这样就不用手写delete然后又有类对象被提前释放或者说忘记写delete导致内存泄露的问题。
#include iostream
#include thread
#include memorystd::thread t;class A{
public:void foo(){std::coutHellostd::endl;}
};int main()
{std::shared_ptrA astd::make_sharedA();std::thread t(A::foo,a);t.join();return 0;
}为什么这里传入a不需要加引用了因为a本身就是一个指针了
入口函数为类的私有成员函数
当foo为私有成员函数时在类外部使用类作用域是调用不到的。 如何解决
使用友元 加一个声明就可以了
互斥量
解决数据共享产生的问题 预期a加的结果为2000000但是没有到因为两个线程同时去拿本应该加2的可能就只能加1了。 在写操作之前对他加锁写完了之后解锁 如果多线程程序每一次的运行结果和单线程运行的结果始终是一样的那么你的线程就是安全的。
死锁
一直在运行等待出现死锁因为t1需要m2的锁,t2需要m1的锁 改变顺序就可以了 互斥量多的时候很容易产生死锁
lock_guard与unique_lock
加完锁一定要解锁这是很严重的一个错误 lock_guard当构造函数被调用时该互斥量自动锁定析构函数被调用时该互斥量自动解锁。lock_guard对象不能复制或移动只能在局部作用域中使用。 lock_guard就不用使用加锁和解锁操作 为这个对象传入一个锁类型 lock_guard源码中就是构造函数和析构函数自动加锁和解锁 unique_lock
延迟加锁、条件变量、超时等 unique_lock在lock_guard基础上多了一个延迟加锁的功能 如果5s之后还没有加锁那么就退出 但是这样是报错的因为给对象传入的类型需要是时间锁 2s内没拿到锁那就直接结束返回了。 正常的加锁是拿不到锁一直等所以有死锁的情况那么我这里超时了直接返回。 正常情况是返回4
std::call_once(单例模式)
单例设计模式确保某个类只能创建一个实例单例实例是全局唯一的因此在多线程环境中使用单例模式时需要考虑线程安全的问题。 比如说日志类全局只需要一个日志对象就可以完成所有的打印操作了 单例模式就是要将构造函数私有化这样才能阻止外部直接创建类对象。 懒汉模式就是一个懒汉只有在需要的时候才起床一样只有需要的时候才实例化饿汉模式就像饿汉遇到食物一样急不可耐类加载完后就完成了对象就创建完成了。 为什么要使用call_once 当多线程进来之后单例就调用了两次违反原则了 call_once能够确保某个函数只会被调用一次 静态成员函数没有this指针这个形参所以无法操作非静态成员。 call_once调用函数需要一个函数一个onceflag
condition_variable(生产者与消费者模型)
生产者不停去安排任务消费者不停地去取任务消费者有很多个也可以理解为生产者为一个老板消费者为很多个打工人。 条件变量需要和互斥锁一起使用
#include iostream
#include thread
#include memory
#include mutex
#include windows.h
#include string
#include condition_variable
#include queuestd::queueintg_queue;
std::condition_variable g_cv;
std::mutex mtx;
void Producer(){for(int i0;i10;i){{std::unique_lockstd::mutex lock(mtx);g_queue.push(i);//通知消费者来取任务g_cv.notify_one();std::couttask:istd::endl;}std::this_thread::sleep_for(std::chrono::microseconds(100));}
}void Consumer(){while(1){std::unique_lockstd::mutex lock(mtx);bool isemptyg_queue.empty();//如果队列为空就要等待g_cv.wait(lock,[](){return !g_queue.empty();});int valueg_queue.front();g_queue.pop();std::coutconsumervaluestd::endl;}
}int main()
{std::thread t1(Producer);std::thread t2(Consumer);t1.join();t2.join();return 0;
}C11实现跨平台线程池
异步开发
future
#include iostream
#include thread
#include memory
#include mutex
#include windows.h
#include string
#include condition_variable
#include queue
#include atomic
#include future
using namespace std;int func(){int i0;for(i0;i1000;i){i;}return i;
}int main()
{std::futureint future_resultstd::async(std::launch::async,func);coutfunc()endl;coutfuture_result.get()endl;return 0;
}
有点相当于又开了个线程去执行函数然后结果保存在future_result里面。 只不过这个线程不需要自己手动去创建
packaged_task
task只是把函数封装到task里面还是需要创建一个线程来跑他的。 而这里task作为一个对象传给线程要用move从左值转换到右值。
promise
在一个线程中产生一个值并在另一个线程中获取这个值。通常与future和async一起使用
#include iostream
#include thread
#include memory
#include mutex
#include windows.h
#include string
#include condition_variable
#include queue
#include atomic
#include future
using namespace std;void func(std::promiseint f){f.set_value(1000);
}int main()
{ std::promiseint f;auto future_resultf.get_future();std::thread t1(func,std::move(f));t1.join();coutfuture_result.get()endl;return 0;
} 或者用引用传入 get() 也会阻塞线程直到promise的执行完毕
原子操作
std::atmoic
除了用互斥量来解决死锁问题原子操作也能保证线程安全。 直接把shared_data变成一个原子变量这个与加锁效果是一样的 原子操作的运行时间 而加锁操作的运行时间 原子操作比解锁效率更高。
load()
其实就是输出这个值
store()
对原子变量进行赋值